View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Open Menu Close Menu
  • Collections
  • All Videos
  • About

More Videos

  • About
  • Summary
  • Transcript
  • Code
  • What’s new in Swift

    Join us for an update on Swift. Discover the latest language advancements, including updates for everyday ergonomics, improved concurrency, and safer high-performance code. Explore workflow and language interoperability improvements and updates in embedded Swift.

    Chapters

    • 0:07 - Introduction
    • 0:44 - Everyday Language Improvements
    • 1:55 - anyAppleOS Availability
    • 3:02 - @diagnose Attribute
    • 3:52 - Module Selectors (::)
    • 5:59 - Library Updates
    • 6:16 - Standard Library
    • 7:31 - Swift Testing Updates
    • 9:29 - Subprocess 1.0
    • 10:14 - Foundation
    • 11:59 - Beyond Apple Platforms
    • 12:35 - Swift–C Interoperability (@C attribute)
    • 15:09 - Swift-Java
    • 16:03 - Editor support
    • 16:44 - WebAssembly (Wasm) & JavascriptKit
    • 18:08 - Embedded Swift
    • 19:59 - Performance Tuning
    • 21:29 - Optimizer Control: @inline(always) & @specialized
    • 24:29 - Ownership System & Noncopyable Types
    • 26:18 - Iterable Protocol & Borrow/Mutate Accessors
    • 28:57 - New Standard Library Types: UniqueBox, UniqueArray, Ref
    • 31:11 - The Future of Swift

    Resources

    • Swift Blog
    • Explore documentation on swift.org
    • Swift Forums
      • HD Video
      • SD Video

    Related Videos

    WWDC26

    • Build real-time apps and services with gRPC and Swift
    • Migrate to Swift Testing
  • Search this video…

    Hi, I'm Becca from the Swift team. My teammate Evan and I are here to tell you about some of the improvements we've made during the development of Swift 6.3 and 6.4. I'll start by showing you some changes to the language that'll streamline your day-to-day coding.

    Then Evan will discuss updates to important libraries and developments in support beyond Xcode and the Apple platforms.

    After that, I'll walk you through some specialized features for tuning performance-sensitive code without compromising on safety.

    Then Evan will finish up by talking about how you can follow along or contribute to Swift's development.

    But let's start with some of the simple improvements that you might use every day.

    Some of them you might barely notice except as little annoyances going away, so let's look at some of the smaller changes first.

    For example, previously if you wanted to use some or any with an optional type, you had to parenthesize it.

    This behavior fell out of Swift's operator precedence rules, but it was a little pedantic. So, in Swift 6.4, you can simply get rid of those parentheses and the compiler will take that to mean the only thing that really makes sense.

    You'll now get a warning if you silently ignore an error thrown from a Swift Concurrency task, reminding you to either handle the error in the task, or save the task and check for the error later. And the old restriction on calling async functions from a defer block is now gone. If you have a class that needs to use @unchecked Sendable because it has a weak var property, you can now change that property to weak let so it's immutable and doesn't stop you from using Sendable checking.

    Or if a type shouldn't be Sendable, you can state that explicitly with the new tilde Sendable syntax. Which, as an added bonus, doesn't stop subclasses from being Sendable.

    And a struct with a mix of internal and private properties will now have a second memberwise initializer that you can use from other files in your project. But there are also some changes you'll definitely notice.

    The Apple ecosystem has grown over the last two decades, and as it has, the availability attributes in your Swift code have grown with it. Last year, Apple began to address this problem by aligning the version numbers of our OS releases. Now, Swift is taking that even further by letting you condense all of those platform names into one: "Any Apple OS". So if the availability lines up on all of the platforms you care about, you can specify all of the OSes at once, or if there are carve-outs, you can use anyAppleOS to establish the default and then add more specific attributes for the exceptions. And this also works for #if os conditions if you want to compile a section of your code out entirely.

    Another thing that changes over the years is APIs.

    As they evolve, older APIs are sometimes deprecated to indicate that you should move to newer versions. But sometimes you can't do that right away, maybe the new API is very different and you need time to adapt.

    Wouldn't it be nice to turn off these warnings temporarily without affecting the rest of your project? Well, now you can. The @diagnose attribute lets you change the behavior of specific warnings inside a particular declaration. So you can tell Swift to ignore the warning group deprecated declaration and make that kind of warning go away in that one place.

    You can also use it to selectively enable warnings that are off by default.

    For example, you could turn on strict memory safety in security-critical functions to make sure you've audited their uses of unsafe APIs.

    Or you can treat certain warnings as errors.

    Here, we've upgraded warnings that will become errors in the future to errors right now.

    All that gives you a lot of flexibility.

    And Swift 6.3 also has a new feature to better handle situations where two modules have APIs with the same name. For example, the Rocket module might have a type representing a real, hundred-meter-tall SaturnV rocket, while the GiftShopToys module has a type representing a child-size model of a SaturnV rocket. If you've imported both of these modules in the same file, Swift won't be able to tell which one you wanted to use, so it'll give you an error.

    When this happens, you've always been able to clarify your code by using the dot syntax, Rocket.SaturnV will first find the Rocket module, then look for the type SaturnV inside it, without ever noticing that there's another SaturnV somewhere else.

    This usually works, but there are some tricky situations where it breaks down. For example, what happens if the module Rocket also has a type Rocket? Well, I'll tell you what happens, Swift prefers type names over module names, so it decides you must mean the type Rocket and then looks inside it for a member called SaturnV.

    When it doesn't find one, it gives you an error. Swift 6.3 has a solution to this problem, just change that dot to a double colon. This new syntax is called a module selector, and the name on the left is always treated as a module name. So Swift will ignore the type Rocket and go straight to the module Rocket, and from there, it'll have no trouble finding the type you're looking for. This syntax also works on the name of a method or property, which is handy if a type gets identically-named methods from extensions in two different modules. After all, calling the wrong method could really ruin someone's day.

    Now, module selectors are super useful when there's a conflict between two modules you don't control.

    Like, if SwiftUI and the database package you're using both have a type called View, a module selector can really save you some trouble.

    It can also be a good idea to use them defensively in macro expansions and other automatically-generated code, since you don't know what else might have been imported into the project. But, we don't recommend you intentionally design your APIs to have name conflicts and then rely on module selectors to distinguish them. Even if your code is unambiguous, some of the error messages and documentation might still be confusing.

    So... don't.

    Now that we've seen what's new in the language, here's Evan to tell you about updates to important libraries.

    All of these language improvements share the same goal of helping you express exactly what you mean without extra noise. That same goal carries into updates to the libraries you use every day.

    The standard library, Swift testing, Subprocess, and Foundation.

    Let's start with updates to the standard library, specifically with new tools for task cancellation, dictionary transformations, and filepath manipulations.

    It's important to check the task cancellation status before starting any expensive work, but there are times where we actually want to do the work even after the task was cancelled, like finishing writing data to disk to avoid corrupting a file.

    Now you can use the task cancellation shield. Inside of the shield, task cancellation checks always return false. It's important to keep this region short, focusing on either finishing or rolling back any work that you already started. Mapping values from dictionaries also received an update. mapValues only passes the old value into the mapping closure, so if you needed the key to compute the new value, you had to construct a new dictionary by hand.

    Now, we can call mapKeyedValues, which passes both the key and the old value into the mapping closure to compute the new value.

    Programs often need to manipulate filepaths. There are subtle differences between how different platforms represent filepaths that can make it tricky to handle them correctly. This year, we added a new filepath type to the standard library, based on the type from Swift System, making it easier to get right.

    Testing in Swift 6.4 offers you more control over the behavior of your tests, allowing you to surface non-fatal issues and dynamically skip tests cases.

    Now you can set the severity level of issues recorded with Issue.record.

    Setting it to a warning means you can surface issues in a test case that are worth investigating, but not worth blocking CI workflows.

    You can cancel tests dynamically by calling the Test.cancel API.

    This is especially powerful with parameterized tests, where you can cancel individual arguments that shouldn't run, rather than running them to completion or failing the test.

    Sometimes you're trying to tackle a flaky test. The swift test command adds new functionality to repeat a test until it either passes or fails, while also allowing you to control the maximum number of repetitions. If you specify that you want to repeat until the tests pass, only failing tests are re-run, saving time by not re-running tests that are already passing.

    Many projects have large test suites that have utilities built on XCTest APIs. In Swift 6.4, XCTest assertion failures are now reported as test issues when called from Swift Testing.

    This means that you can migrate to Swift Testing without worrying about accidentally losing test coverage along the way. And the interoperability also works in the other direction too, Swift Testing APIs, like the #expect macro work when called from an XCTestCase. This means you can build helper APIs with Swift Testing, and they'll have consistent behavior regardless of whether they're called from XCTest or Swift Testing.

    If you're working in an existing project, you might already be calling XCTest assertions from Swift Testing and vice-versa.

    To make this transition easier, these issues are reported as warnings by default. You can opt into promoting them to test failures in the Xcode build settings.

    To learn more about Swift Testing interoperability and migration strategies, check out "Migrate to Swift Testing".

    Last year, we announced the Subprocess package containing modern APIs for launching subprocesses. This year, we are releasing Subprocess 1.0, incorporating your feedback from real-world use.

    The API refinements include a simplified execution type, improved error handling, and convenience APIs for easily streaming process output.

    Cross-platform support is also greatly improved, including platform-specific process file descriptors and termination statuses, to more accurately reflect the semantics on different platforms. Here is an example of the refined API in Subprocess 1.0.

    When calling the run method to launch a subprocess, the standard output and standard error streams can be included in the execution object as AsyncBufferSequences. This model guarantees that each stream is only created once. The new strings() method on AsyncBufferSequence makes it easy to read the output of a subprocess line-by-line.

    This API respects graphene cluster boundaries, so you don't have to worry about multi-byte characters getting split.

    Finally, let's talk about improvements to Foundation.

    ProgressManager is a new type in Foundation for progress reporting. It's designed to work well with async/await style concurrency it cleanly separates progress composition from progress reporting, and provides a structured, type-safe mechanism for attaching additional metadata.

    We announced Swift-Foundation two years ago, an effort to migrate Foundation to a safe, consistent, cross-platform codebase, written in Swift. This year, we continued that effort, replacing decades of Objective-C with modern Swift.

    This year, we modernized more parts of Data, resulting in improvements across the board, including faster span accesses, equality checks, iteration, and mutation.

    On Apple platforms, bridging between Data and NSData is also faster.

    NSURL and CFURL were unified to a single Swift implementation.

    Leveraging Swift makes these types run faster and use less memory. Migrating a library as large and mature as Foundation is only possible because of Swift's language interoperability.

    You can add entirely new APIs in Swift, and you can migrate the implementation of existing APIs to Swift without changing the API surface.

    In addition to crossing language boundaries, many real-world projects extend into services, devices, web components, cross-platform clients, and more. At Apple, we use Swift in every part of the OS, in apps like Weather, in services like the realtime phone call spam detection, in the kernel itself, and all of the way down to the lowest layers of firmware. Swift is designed to be a language that you can reach for across every layer of your software stack.

    To make it easier to use in your existing software systems, Swift 6.4 extends language interoperability, improves cross-platform IDE support, and makes it easier and safer to bring your Swift code to other environments like the web and embedded devices.

    You've always been able to import C into Swift with ease. Swift 6.4 allows you to expose functions written in Swift back to C.

    You've likely seen or used the @objc attribute when migrating your apps from Objective-C to Swift. The @C attribute works the same way, but for C.

    The @C attribute applies to functions that operate on C-compatible types. Any type you can import from C to Swift can also be used in functions that are exported from Swift to C, like integers pointers, imported C structs, and enums with raw integer value types. And, the compiler prevents you from accidentally passing types that are incompatible with C. Let's see the @C attribute in action. I'm working on an app for scheduling rocket launches. We'll focus on the code tracking the launch windows.

    It's currently written in C, but we're migrating to Swift for memory safety and improving developer ergonomics. Let's use the new features in Swift 6.4 to rewrite portions of the application from C. There are currently two functions declared in the header, one to get the length of a launch window, and another to compute the total time spent in a collection of launch windows, allowing us to compute launch pad utilization.

    Let's start by replacing the C implementation of the function computing the length of a launch window.

    We can use the @c and @implementation attributes together to implement a C function without creating a C declaration for it since it already exists in the original header file.

    Next, we'll provide an implementation for the function computing the total time spent in a launch window, across many launch windows.

    Functions are imported verbatim when you're implementing them in Swift. We can translate the types into native Swift types allowing us to use the ergonomics of Swift to reimplement our C functions. Safe interop features provide safe wrappers when we call the functions, so instead of passing the array and count separately, we can pass it a span. It's easier to write, and it's safe! While we're working on this, I want to add a new function that gets the average launch window length.

    We don't use the @implementation attribute here because the function isn't declared in the original C header. The Swift compiler emits the appropriate function declaration into the generated C interop header instead, so we can call the new function from our C code. Swift automatically bridges Swift Spans to C. Now, Swift C++ interoperability also supports bridging between Swift and C++ 20 spans. This declaration imports to Swift with a span, so you can pass a span in directly. Interoperability is key to bringing Swift into existing codebases written in other languages.

    Swift-Java is the package that enables interoperability between Swift and Java. It now supports calling async and throwing Swift functions from Java. It captures more features of the generics system, including constrained extensions, and conforming Java classes to Swift protocols. All of these improvements make calling Swift code from Java and Kotlin feel natural on Android. And you can now download an official Swift SDK for Android on swift.org. The latest version of the Swift extension for VSCode adds new integration with Swiftly, making it easy to install toolchains from swift.org, right from your editor. So now you'll always have the right toolchain for any platform, right at your fingertips.

    Last year, we added the Swift extension to the Visual Studio marketplace.

    This year, we've added it to the OpenVSX marketplace, making the integrated Swift experience available to new editors including VSCodium, Cursor, Kiro, and Antigravity. The latest version of the plugin makes it easier to get started with Swift than ever before with a checklist that guides you through installing Swift, creating a new project, running your code, setting up tests, and generating documentation.

    If you have Swiftly installed, it can help manage your toolchains. I'm installing a nightly toolchain so that I can play with the new language features targeting Web Assembly and embedded platforms.

    The open source toolchain we just installed can compile to Web Assembly. Wasm support in Swift means that you can use the same language to write your native apps, your backend webservers, and your frontend too. Let's look at some of the improvements in the Javascript interoperability story coming out of the open-source project JavascriptKit.

    Bridging between Swift and Javascript used to involve a lot of dynamic lookups and hoping that types would match up.

    The most recent efforts in JavascriptKit have made bridging between the languages safer and faster. The code looks like native Swift code, but it's making calls to WebGL through Javascript.

    The popular note-taking app, Goodnotes, recently implemented a web-based interface in addition to their native iOS app. The cost of moving their core app to another language, working through the bugs, and then maintaining two codebases was too high.

    They took their existing, battle-tested, Swift code, and compiled it for the web using Wasm.

    And with the improvements to JavaScriptKit, their benchmarking found the safe bridging to be 35 to 40 times faster than the dynamic bridging. Wasm support in Swift means you can take your Swift code running in your native iOS applications and get it running as part of a webapp.

    Unlike with a native application though, you have to send the compiled code to each device every time they visit your site. There are CDNs to help, but big binaries can quickly eat into yours, and your customer's data. This means that size is a bigger concern than ever. With embedded Swift, we can take advantage of the ergonomics of Swift in more constrained environments. We stripped down the language to make it fit, and now, as we learn how people are using Swift in these environments, we are growing the available subset of the language.

    Embedded Swift now has support for existential types. This means you can work with multiple types conforming to a protocol stored in an array or passed to a function.

    Typed throws are great when you know the error type, but they're limited to a specific error type. Using the same underlying machinery for handling existential types, embedded Swift now supports untyped throws.

    The debugger needs extra metadata about type layout to display variables. To keep binary size down, embedded Swift does't include that data in the binary itself.

    Furthermore, many embedded systems only leave you with a core dump of the memory state when the program crashed, so you're not even debugging a live process. Swift 6.4 saves all of the necessary metadata into the DWARF debug info, keeping binary sizes down, while greatly improving the experience debugging an embedded Swift coredump.

    These are just a few of the improvements we made this year, bridging the gap between full and embedded Swift.

    While the subset of Swift that works on embedded platforms is growing, it is still a subset of the language. Diagnostics in the EmbeddedRestrictions warning group identify language features that aren't available in embedded contexts.

    If you're working with a library that supports both embedded and full Swift, you may need to expose functions that use features that aren't available in embedded contexts. The @diagnose attribute that Becca showed us earlier lets us control these diagnostics. Embedded code often runs on incredibly constrained hardware environments. That's why it's critical to get the most out of every clock cycle. Back to Becca to talk about how to squeeze performance from your Swift code.

    Swift is designed to have great performance even when you've written the most straightforward, expressive implementation of your logic.

    But when you're doing a lot of computation, or running in constrained environments like embedded systems, sometimes it's worth complicating your code to squeeze out just a little bit more when it counts.

    You usually won't need these advanced performance features, but when you do, you'll be glad you have them.

    I'm going to focus on two areas we've worked on this year, explicitly controlling optimizer decisions, and further extending the ownership system to safely prevent unnecessary copying.

    The Swift compiler's optimizer applies dozens of techniques to make your code faster, but some of the most powerful ones can be counterproductive when they're applied incorrectly.

    These involve duplicating code so it can be customized for a particular situation, but if the customization doesn't pay off, you could end up with a program that's larger and slower instead of smaller and faster.

    For example, one of the most important optimizations the compiler performs is inlining, replacing function calls with their implementations, and then optimizing those implementations for the specific call site.

    When inlining pays off, the program does less work to get the same result, but when it doesn't, it just makes the binary bigger without making it any faster. To keep that from happening, the optimizer analyzes the function and call site to decide whether inlining is likely to pay off, but sometimes it makes the wrong decision, so you might want a way to force the issue.

    Swift has long had an @inline(never) attribute, that completely forbids inlining, useful when you know that inlining the function will never be a win. In Swift 6.4, there is now a matching @inline(always) attribute which forces the compiler to inline even when the optimizer isn't sure it'll be a good idea.

    Sometimes it still won't be able to though, like when you call an object method that might be overridden, so consider using final with @inline(always) for methods of classes.

    Another important optimization is specialization cloning a generic function for a specific concrete type, eliminating generic overhead and often enabling further optimization. Specializing a function only helps if the optimizer knows that you're going to use it with that type, but sometimes, especially in libraries, the compiler can't see how the function will be used.

    Swift 6.3 introduces the @specialized attribute to give you direct control over this.

    Inside the attribute, you write a where clause constraining some or all of the generic parameters and Swift will generate a specialized version of the function with those constraints.

    So if you have some slow generic code that gets used a lot with one or two specific types, you can let Swift know that it needs to prioritize them. But the biggest improvements we've made for performance tuning are to the ownership system.

    To understand what we've done, let's start by reviewing what we already have.

    A lot of performance problems in Swift boil down to unnecessarily copying data. You have a piece of data in one place, you need it in another, so you copy the data across to new storage. Sometimes these components are big, like the model and view layers of your app, or sometimes they're small, like the two variables on either side of a for loops in keyword, but the basic pattern is the same.

    The way to solve slow-downs due to copying is to recognize that, in certain situations, a copy is unnecessary. If you know that the storage will stay allocated, and that both of the components using it will follow Swift's exclusivity rules so they don't mutate data they both have access to, then you don't need to copy the data you just need to grant access to the existing storage. The simplest way to avoid copying is to put the data in an object and pass that object to the other component.

    This is often good enough, but it doesn't entirely eliminate the problem. After all, objects are reference-counted, and passing an object changes its reference count. Releasing and retaining an object has less overhead than copying a large value, but it still might be too slow for the most performance-sensitive code.

    When objects aren't an option, you've traditionally had to pass an UnsafePointer to the storage instead. But the problem with doing that is right in its name, UnsafePointers are unsafe. Sharing storage like this is only safe because both components are following certain rules, but the compiler has no idea about those rules and can't make sure that each side will hold up its end of the bargain.

    Component 1 could mutate data that Component 2 expected to remain unchanged. Or it could deallocate the storage while Component 2 is still using it.

    You're back to a world with no memory safety, like the C languages had.

    So a few years ago, we started working on a better solution. We codified the set of guarantees needed to safely share storage as a borrow. As long as Component 2 is borrowing the storage, both Components can only read it, not write it. Component 2 has to finish using the storage first, and when it does, Component 1 regains full control.

    Mutation is similar, except the other component is completely blocked from accessing the storage. This ensures that it doesn't read half-updated data or behave differently depending on when the other component chooses to write back its changes. And whether it's borrowing or mutating, Swift can verify at compile time that both components are following the rules.

    But our goal has always been to support these advanced use cases without affecting how you write ordinary Swift code. That's required careful, incremental design of ownership features. This has been a multi-year process and it's still not over, but this year we've taken a few more steps forward. For example, the Equatable, Comparable, and Hashable protocols can now be used on noncopyable types.

    And Equatable and Comparable can also be used with non-escapable types.

    This lets types tuned for performance and safety take advantage of some of the most universal capabilities that ordinary Swift types have. Associated types can also now be non-copyable or non-escapable.

    This opens up powerful new capabilities for high-performance protocol-driven development, like the Iterable protocol seen here.

    Its element type is non-copyable and its iterator type is both non-copyable and non-escapable. Of course, that doesn't mean you can't use a copyable or escapable type for these, it just means that the protocol doesn't require it. Gosh, though, that Iterable type looks really handy. Don't you wish it were real? Well, good news, it is! In Swift 6.4, for loops support a new Iterable protocol. The Sequence protocol we all know and love works by copying the elements out of the sequence, the Iterable protocol allows the for loop to borrow them instead.

    This means it works with non-copyable elements, and also that it doesn't need to perform reference counting when it's working with objects or copy-on-write types. Plus, it can optionally throw an error during the loop, just like an ASYNC Sequence can. However, like any borrow, exclusivity checking prohibits you from mutating the Iterable while you're looping over it which isn't necessarily a bad thing, since this was often a performance trap with Sequences. Because of this behavior difference, the for loop will prefer the Sequence protocol if available, and fall back to Iterable otherwise.

    Much like a Sequence, an Iterable works by creating an iterator for the for loop to retrieve the elements from.

    But unlike a sequence, it retrieves elements in batches. The for loop will ask the iterator for a span of elements and go through them one-by-one. Then ask for another span and visit those, too.

    When it runs out of elements, it returns an empty span, which terminates the for loop. This batching design makes the loop a lot more efficient, especially for types that can just return everything in one big span.

    Swift 6.4 also makes a major improvement to accessors.

    To understand why it's important, consider this UniqueBox struct.

    It automatically manages a pointer to a large value and provides a computed property to access it. Unfortunately, as it's written right now, this property has a serious performance problem. Let's see why.

    Suppose you put an InlineArray of 256 Ints in a UniqueBox. InlineArrays are, well, inline, so on a 64-bit device, that's gonna be a two-kilobyte struct. Not something you want to be copying around all the time! Which is a problem, because get and set work by copying the data. To change one Int in the array, you have to copy the whole thing out and then back again.

    That's not going to help your performance very much! Fortunately, there's now a better option, you can switch from get and set to borrow and mutate. The new borrow accessor gives you read-only access to shared storage without copying it, while the mutate accessor gives you exclusive access to modify it in place. Once you've switched, Swift can just mutate the element in the original array without copying anything.

    And, as a nice little bonus, the new accessors mean UniqueBox can also handle non-copyable values. The borrow and mutate accessors are a big help for both performance and expressivity, and we're excited they're ready for everyone to use. Gosh, though, that UniqueBox type looks really handy. Don't you wish it... Okay, okay, you know how that ends, I won't do that spiel again. Yes, UniqueBox is a real type that's now in the standard library. There are also some other new APIs that save you from writing unsafe code, "Unique Array" is a lot like an ordinary Swift Array, except that it's non-copyable. That means you can store non-copyable elements and avoid reference counting overhead without limiting yourself to a fixed size.

    The withTemporaryAllocation function uses an OutputSpan instead of an UnsafeMutableBufferPointer to ensure that temporary memory is handled safely.

    The Continuation type checks at compile time that you only resume it once, making it even safer than a CheckedContinuation but just as efficient as an UnsafeContinuation. And there's also one more pair of types I want to tell you about, but they're not improved versions of an existing API, they bring new capabilities to the language. A Ref is a bit like a Span, but for one value instead of many. It's sort of like a container for a borrow or mutation, that can be stored in variables, passed and returned from functions, and used in generic types. You can make an instance of the Ref type from a read access by borrowing storage, or an instance of the MutableRef type from a write access by using the prefix ampersand. These types can be used to create new APIs that were impossible to write before, like a method that returns a Mutable Ref for one of its properties, but they can also be used to address performance issues.

    For example, consider this updateCount function. It looks up a dictionary key every time it needs to increment it, even though the key is always the same. You usually want to hoist repeated work like that out of the loop so you only have to do it once, but until now, the only way to do a dictionary lookup and just sort of hold it open for a while, was by moving the loop into a function and passing the lookup as an inout parameter. A pretty obscure trick! MutableRef gives you a better way. Now you can make a MutableRef from the dictionary lookup once, before the loop starts, and then use it when you want to mutate the dictionary entry. Refs are non-escapable, so Swift knows the access ends when the variable goes out of scope. All these new ownership features combine to make speeding up your most performance sensitive code safer and easier than ever. The ownership system isn't the only work that's still in progress. Let's hand it back to Evan to tell you about the future of Swift. The features we covered today were developed in open source, improving the overall experience across the Apple OS's, Linux, Windows, and beyond. Here are some more future developments happening in the open source community that you can get involved with.

    Last year, we announced that we were open sourcing Swift Build, the build system in Xcode. Swift Build is now the default build system backend for Swift Package Manager, improving the consistency between Swift Package builds and what you see from Xcode. Joining the growing list of workgroups are the build and packaging workgroup, addressing the build and packaging needs of the Swift community. The networking workgroup, designing the next generation of cross-platform networking APIs. And the Windows workgroup, improving the Swift experience on Windows. This year, the Android work group released the first Swift SDK for Android as part of Swift 6.3. This means it is now possible to share Swift code between Android and iOS apps. If you're interested in participating in the development of the Swift ecosystem, please join us on the Swift forums at forums.swift.org. We would love to have your unique feedback.

    Thank you for following along with us today to learn more about what's new in Swift. Whether you've submitted a bug report, posted a pull request, joined us at an event, or participated on the forums, your contributions help shape the future of Swift making programming safer and more approachable for everyone. Thank you!

    • 1:12 - Better Swift Concurrency diagnostics (catching in the task)

      Task {
          do {
              try lander.fly(to: moon)
          }
          catch {
              lander.abort()
          }
      }
    • 1:21 - Better Swift Concurrency diagnostics (saving the task for later)

      let landingTask = Task {
          try lander.fly(to: moon)
      }
      
      defer {
          await orbiter.rendezvous(with: lander)
      }
      
      try await orbiter.justHangOut(waitingFor: landingTask)
    • 1:27 - Better 'Sendable' conformances

      final class Spacecraft: Sendable {
          ...
          weak let dockedAt: SpaceStation?
          ...
      }
      
      class Mission: ~Sendable { ... }
      
      class CrewedMission: Mission, @unchecked Sendable { ... }
    • 1:48 - More accessible memberwise initializers

      struct Briefing {
          internal var topic: String
          internal var scheduledAt: Date
          private  var attendees: [Person] = []
      }
      
      // Generated memberwise initializers:
      // extension Briefing {
      //     private init(topic: String, scheduledAt: Date, attendees: [Person] = []) { 
      //          self.topic = topic
      //          self.scheduledAt = scheduledAt
      //          self.attendees = attendees
      //     }
      // 
      //     internal init(topic: String, scheduledAt: Date) {
      //          self.topic = topic
      //          self.scheduledAt = scheduledAt
      //          self.attendees = []
      //     }
      // }
    • 2:03 - 'anyAppleOS' availability (before)

      extension Mission {
          @available(macOS 27, iOS 27, watchOS 27, tvOS 27, visionOS 27, *)
          func showStatus() { ... }
      
          @available(macOS 27, iOS 27, watchOS 27, visionOS 27, *)
          @available(tvOS, unavailable)
          func launch() { ... }
        
          #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
          func makeLiveActivityWidget() -> some Widget { ... }
          #endif
      }
    • 2:17 - 'anyAppleOS' availability (after)

      extension Mission {
          @available(anyAppleOS 27, *)
          func showStatus() { ... }
      
          @available(anyAppleOS 27, *)
          @available(tvOS, unavailable)
          func launch() { ... }
        
          #if os(anyAppleOS)
          func makeLiveActivityWidget() -> some Widget { ... }
          #endif
      }
    • 2:40 - Controlling warnings with '@diagnose'

      @diagnose(DeprecatedDeclaration, as: ignored, reason: "Flying with surplus hardware")
      func makeApolloSoyuzMission() -> Mission {
          CrewedMission(
              rocket: makeSaturnIRocket(),
              payload: makeApolloCSM(),
              crew: [.daniellePoole, .nathanMorrison]
          )
      }
      
      @diagnose(StrictMemorySafety, as: warning)
      func uplinkCommand(from receiver: inout Receiver, to computer: inout Computer) {
          let commandSize = receiver.receiveInt()
          receiver.withReceivedData(byteCount: commandSize) {
              computer.receiveUplinkedCommand($0)
          }
      }
      
      @diagnose(ErrorInFutureSwiftVersion, as: error)
      func fetchPosition() -> (x: Double, y: Double, z: Double) {
          return self.rotation
      }
    • 3:47 - Clarifying code with module selectors

      import Rocket
      import GiftShopToys
      
      let rocket1 = SaturnV()            // could mean `Rocket::SaturnV` or `GiftShopToys::SaturnV`
      let rocket2 = Rocket.SaturnV()     // prefers `Rocket::Rocket.SaturnV`
      let rocket3 = Rocket::SaturnV()    // correctly finds `Rocket::SaturnV`
    • 5:00 - Clarifying code with module selectors (module selectors work on members, too)

      //
      // Module Chemistry
      //
      
      public protocol Flammable { ... }
      
      extension Flammable {
          /// Set `self` on fire.
          public func fire() { ... }
      }
      
      //
      // Module HumanResources
      //
      
      import Chemistry
      
      public protocol Employee { ... }
      
      extension Employee {
          /// Remove `self` from job.
          public func fire() { ... }
      }
      
      public class LaunchPadTechnician: Employee, Flammable { ... }
      
      //
      // Module main
      //
      
      import HumanResources
      import Chemistry
      
      let launchPadTechnician = LaunchPadTechnician(...)
      
      launchPadTechnician.HumanResources::fire()
    • 6:26 - Task cancellation

      // Radio for help
      
      extension Radio {
        func send(_ data: [UInt8] {
          if Task.isCancelled { return }
          // ...
        }
      }
        
      extension EmergencyTransponder {
        func sendSOS() {
          radio.send(makeSOSPacket())
        }
      }
    • 6:40 - Task cancellation shield

      // Radio for help
      
      extension Radio {
        func send(_ data: [UInt8] {
          if Task.isCancelled { return }
          // ...
        }
      }
        
      extension EmergencyTransponder {
        func sendSOS() {
          withTaskCancellationShield {
          	radio.send(makeSOSPacket())
          }
        }
      }
    • 6:53 - Constructing a new dictionary

      // Map values with keys
      
      func makeCalendarDisplayNames(for missions: [Mission: LaunchWindow]) -> [Mission: String] {
          let new: [Mission: String] = .init(
              uniqueKeysWithValues: missions.lazy.map { mission, launchWindow in
                  (mission, makeDisplayName(for: mission, in: launchWindow))
              }
          )
          return new
      }
    • 7:06 - Dictionary.mapKeyedValues

      // Map values with keys
      
      func makeCalendarDisplayNames(for missions: [Mission: LaunchWindow]) -> [Mission: String] {
          missions.mapKeyedValues { mission, launchWindow in
              makeDisplayName(for: mission, in: launchWindow)
          }
      }
    • 7:14 - The new FilePath type

      // FilePath handling macOS-named resources
      
      var path: FilePath = "/var/www/static"
      path.components.append("WWDC")
      print(path.components)
      // [ "var", "www", "static", "WWDC" ]
      
      var path: FilePath = "/var/www/static/..namedresource/rsrc"
      print(path.components)
      // [ "var", "www", "static" ]
    • 7:41 - Issue Severity

      // Issue severity
      
      @Test(arguments: allRockets)
      func testBurn(rocket: Rocket) throws {
          rocket.burn(for: .seconds(150))
          let remaining = rocket.propellantKg / rocket.totalPropellantKg
      
          if remaining < 0.10 {
              Issue.record(
                  "\(rocket.name) remaining fuel is below 10% reserve target",
                  severity: .warning
              )
          }
      
          #expect(remaining > 0.02, "\(rocket.name) propellant critically low - abort")
      }
    • 7:52 - Test Cancellation

      // Test Cancellation
      
      @Test(arguments: allRockets)
      func testBurn(rocket: Rocket) throws {
          // solid-fuel rocket engines can't be stopped
          if rocket.engineType == .solid {
              try Test.cancel("\(rocket.name) has solid fuel")
          }
       
          rocket.burn(for: .seconds(150))
          let remaining = rocket.propellantKg / rocket.totalPropellantKg
      
          if remaining < 0.10 {
              Issue.record(
                  "\(rocket.name) remaining fuel is below 10% reserve target",
                  severity: .warning
              )
          }
      
          #expect(remaining > 0.02, "\(rocket.name) propellant critically low - abort")
      }
    • 8:34 - XCTest interoperability: Using XCTest from Swift Testing

      // XCTest interoperability: Using XCTest from Swift Testing
      
      func checkedTransmitAndReceive(on radio: Radio,
                                     packet: Packet,
                                     expectedByteCount: Int) throws -> [UInt8] {
          try radio.transmit(bytes: packet.data)
          let bytes = try radio.receive()
          XCTAssertEqual(bytes.count, expectedByteCount)
          return bytes
      }
      
      @Test
      func pingTest() throws {
          let radio = Radio()
          let bytes = try checkedTransmitAndReceive(on: radio, packet: .ping, expectedByteCount: 8)
          #expect(bytes == [0x00, 0x00, 0xf0, 0x37, 0x0f, 0xc7, 0x00, 0x01])
      }
    • 8:48 - XCTest interoperability: Using Swift Testing from XCTest

      // XCTest interoperability: Using Swift Testing from XCTest
      
      class RadioTests: XCTestCase {
          func testPingPacketTransmission() {
              let radio = Radio()
              let bytes = try checkedTransmitAndReceive(on: radio,
                                                        packet: .ping,
                                                        expectedByteCount: 8)
      
              #expect(bytes == [0x00, 0x00, 0xf0, 0x36, 0x0f, 0xc7, 0x00, 0x02])
          }
      }
    • 10:01 - Subprocess Output Stream

      // Subprocess output streaming
      
      let result = try await Subprocess.run(.name("ls"),
                                            input: .none,
                                            output: .sequence,
                                            error: .string(limit:4096)) { execution in
      		execution.standardOtput.strings().filter { $0.hasSuffix(".obj") }
      }
      
      for try await objectFiles in result.closureOutput {
        	print("Object file: \(objectFile)")
      }
    • 10:37 - Progress Manager - Concurrency

      // Progress reporting - Concurrency
      
      let manager = ProgressManager(totalCount: 100)
      try await rocket.launch(mission.subprogress(assigningCount: 100))
      
      extension Rocket {
          func launch(_ progress: consuming Subprogress? = nil) async throws {
              let stage = progress?.start(totalCount: 3)
              try await ignite(); stage?.complete(count: 1)
              try await liftoff(); stage?.complete(count: 1)
              try await stageSeparation(); stage?.complete(count: 1)
          }
      }
    • 10:37 - Progress Manager - progress reporting

      // Progress reporting - progress reporting
      
      let manager = ProgressManager(totalCount: 100)
      try await rocket.launch(mission.subprogress(assigningCount: 100))
      
      Task {
          for await update in Observations({ mission.fractionCompleted }) {
              print("πŸš€ Mission \(Int(update * 100))%")
          }
      }
    • 10:37 - Progress reporting - metadata

      // Progress reporting - metadata
      
      extension Rocket {
          func ascend(_ progress: consuming Subprogress) async throws {
              let stage = progress.start(totalCount: 3)
              stage.detlaV = 3_400; try await burn(); stage.complete(count: 1)
              stage.detlaV = 2_100; try await stageSeparation(); stage.complete(count: 1)
              stage.detlaV = 1_800; try await coast(); stage.complete(count: 1)
          }
      }
      
      print("Ξ”v to orbit: \(mission.summary(of: \.deltaV)) m/s")
    • 20:56 - Directly control inlining (source code)

      func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
          var result = makeInts(randomized: false)
        
          for value in values {
              result[Int(value)] += 1
          }
        
          return result
      }
      
      func makeInts(randomized: Bool) -> [256 of Int] {
          if randomized {
              InlineArray { _ in Int.random(in: (.min)...(.max)) }
          } else {
              InlineArray(repeating: 0)
          }
      }
    • 21:01 - Directly control inlining (inlined, but not optimized)

      func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
          var result = if false {                                                  //
                           InlineArray { _ in Int.random(in: (.min)...(.max)) }    //
                       } else {                                                    // Inlined code
                           InlineArray(repeating: 0)                               //
                       }                                                           //
      
         for value in values {
              result[Int(value)] += 1
          }
          return result
      }
      
      func makeInts(randomized: Bool) -> [256 of Int] {
          if randomized {
              InlineArray { _ in Int.random(in: (.min)...(.max)) }
          } else {
              InlineArray(repeating: 0)
          }
      }
    • 21:07 - Directly control inlining (inlined and optimized)

      func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
          var result = InlineArray(repeating: 0)    // Inlined and optimized code
      
         for value in values {
              result[Int(value)] += 1
          }
          return result
      }
      
      func makeInts(randomized: Bool) -> [256 of Int] {
          if randomized {
              InlineArray { _ in Int.random(in: (.min)...(.max)) }
          } else {
              InlineArray(repeating: 0)
          }
      }
    • 21:30 - Directly control inlining (preventing inlining)

      @inline(never)
      func makeInts(randomized: Bool) -> [256 of Int] {
          if randomized {
              InlineArray { _ in Int.random(in: (.min)...(.max)) }
          } else {
              InlineArray(repeating: 0)
          }
      }
    • 21:39 - Directly control inlining (forcing inlining)

      @inline(always)
      func makeInts(randomized: Bool) -> [256 of Int] {
          if randomized {
              InlineArray { _ in Int.random(in: (.min)...(.max)) }
          } else {
              InlineArray(repeating: 0)
          }
      }
    • 21:55 - Making generic functions faster with '@specialized'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
          var result = makeInts(randomized: false)
        
          for value in values {
              result[Int(value)] += 1
          }
        
          return result
      }
      
      // Note: Specialized function doesn't actually have a directly callable name.
      func `histogram of [UInt8]`(of values: [UInt8]) -> [256 of Int] {    //
          var result = makeInts(randomized: false)                         //
                                                                           //
          for value in values {                                            //
              result[Int(value)] += 1                                      // Specialized code
          }                                                                //
                                                                           //
          return result                                                    //
      }                                                                    //
    • 22:17 - Making generic functions faster with '@specialized'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ (explicitly requesting specialization)

      @specialized(where Values == [UInt8])
      func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
          var result = makeInts(randomized: false)
        
          for value in values {
              result[Int(value)] += 1
          }
        
          return result
      }
      
      // Note: Specialized function doesn't actually have a directly callable name.
      func `histogram of [UInt8]`(of values: [UInt8]) -> [256 of Int] {    //
          var result = makeInts(randomized: false)                         //
                                                                           //
          for value in values {                                            //
              result[Int(value)] += 1                                      // Specialized code
          }                                                                //
                                                                           //
          return result                                                    //
      }                                                                    //
    • 25:46 - Associated types can be '~Copyable' and '~Escapable'

      protocol Iterable<Element, Failure>: ~Copyable, ~Escapable {
          associatedtype Element: ~Copyable
          associatedtype IterableIterator: IterableIteratorProtocol<Element, Failure>, ~Copyable, ~Escapable
          associatedtype Failure: Error = Never
      
          func makeIterableIterator() -> IterableIterator
        
          var underestimatedCount: Int { get }
      }
      
      protocol IterableIteratorProtocol<Element, Failure>: ~Copyable, ~Escapable {
          associatedtype Element: ~Copyable
          associatedtype Failure: Error = Never
      
          mutating func nextSpan(maximumCount: Int) throws(Failure) -> Span<Element>
        
          mutating func skip(by maximumOffset: Int) throws(Failure) -> Int
      }
    • 27:28 - The problem with existing accessors

      @safe public struct UniqueBox<Value>: ~Copyable {
          private let valuePointer: UnsafeMutablePointer<Value>
      
          public init(_ value: consuming Value) {
              valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
              valuePointer.initialize(to: value)
          }
      
          public var value: Value {
              get { valuePointer.pointee }
              set { valuePointer.pointee = newValue }
          }
      
          deinit {
              valuePointer.deinitialize(count: 1)
              valuePointer.deallocate()
          }
      }
    • 28:19 - 'borrow' and 'mutate' accessors

      @safe public struct UniqueBox<Value: ~Copyable>: ~Copyable {
          private let valuePointer: UnsafeMutablePointer<Value>
      
          public init(_ value: consuming Value) {
              valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
              valuePointer.initialize(to: value)
          }
      
          public var value: Value {
              borrow { valuePointer.pointee }
              mutate { &valuePointer.pointee }
          }
      
          deinit {
              valuePointer.deinitialize(count: 1)
              valuePointer.deallocate()
          }
      }
    • 30:14 - Using 'MutableRef' to eliminate repeated accesses (with un-hoisted access)

      func updateCount<Key: Hashable>(
          for key: Key,
          from sets: [Set<Key>],
          in counts: inout [Key: Int]
      ) {
          for set in sets {
              if set.contains(key) {
                  counts[key, default: 0] += 1
              }
          }
      }
    • 30:34 - Using 'MutableRef' to eliminate repeated accesses (hoisted by 'inout' parameter)

      func updateCount<Key: Hashable>(
          for key: Key,
          from sets: [Set<Key>],
          in counts: inout [Key: Int]
      ) {
          func updateCountImpl(count: inout Int) {
              for set in sets {
                  if set.contains(key) {
                      count += 1
                  }
              }
          }
          
          updateCountImpl(count: &counts[key, default: 0])
      }
    • 30:41 - Using 'MutableRef' to eliminate repeated accesses (hoisted by 'MutableRef')

      func updateCount<Key: Hashable>(
          for key: Key,
          from sets: [Set<Key>],
          in counts: inout [Key: Int]
      ) {
          var countRef = MutableRef(&counts[key, default: 0])
      
          for set in sets {
              if set.contains(key) {
                  countRef.value += 1
              }
          }
      }
    • 0:07 - Introduction
    • A preview of the session's four topics: language improvements, library updates, cross-platform support, and performance tuning in Swift 6.3 and 6.4.

    • 0:44 - Everyday Language Improvements
    • Quality-of-life changes land in Swift 6.4, including optional parentheses removal, concurrency task warnings, weak let, ~Sendable, and a new memberwise initializer.

    • 1:55 - anyAppleOS Availability
    • Swift now lets you condense multi-platform availability attributes into a single anyAppleOS condition, reducing boilerplate across iOS, macOS, watchOS, and more.

    • 3:02 - @diagnose Attribute
    • The new @diagnose attribute gives fine-grained control over warnings within a specific declaration, letting you suppress, enable, or promote them to errors.

    • 3:52 - Module Selectors (::)
    • Swift 6.3 introduces double-colon module selector syntax to unambiguously reference a type or member from a specific module when name conflicts arise.

    • 5:59 - Library Updates
    • Updates across four key libraries: the standard library, Swift Testing, Subprocess, and Foundation.

    • 6:16 - Standard Library
    • New additions include a task cancellation shield, mapKeyedValues for dictionaries, and a cross-platform FilePath type.

    • 7:31 - Swift Testing Updates
    • Swift Testing gains configurable issue severity, dynamic test cancellation, flaky test repetition, and improved two-way interoperability with XCTest.

    • 9:29 - Subprocess 1.0
    • Subprocess reaches 1.0 with a refined API, improved error handling, convenient line-by-line output streaming, and expanded cross-platform support.

    • 10:14 - Foundation
    • Foundation gains a new ProgressManager type and continues its Swift migration, with performance improvements to Data, NSURL, and CFURL.

    • 11:59 - Beyond Apple Platforms
    • Swift 6.4 extends language interoperability and broadens its reach to new environments including web, Android, and embedded devices.

    • 12:35 - Swift–C Interoperability (@C attribute)
    • The new @C attribute lets you expose Swift functions directly to C, enabling safe, incremental migration of C codebases to Swift.

    • 15:09 - Swift-Java
    • The Swift-Java package now supports async and throwing Swift functions from Java, constrained extensions, and conforming Java classes to Swift protocols.

    • 16:03 - Editor support
    • The Swift VSCode extension adds Swiftly integration for toolchain management and is now available on the OpenVSX marketplace for editors like Cursor and VSCodium.

    • 16:44 - WebAssembly (Wasm) & JavascriptKit
    • Swift can now compile to WebAssembly, with JavascriptKit improvements delivering up to 40x faster safe bridging between Swift and JavaScript.

    • 18:08 - Embedded Swift
    • Embedded Swift expands its language subset with existential types, untyped throws, and improved DWARF debug info for coredump debugging on constrained hardware.

    • 19:59 - Performance Tuning
    • Two areas of advanced performance work: explicit optimizer control and extensions to the ownership system to prevent unnecessary copying.

    • 21:29 - Optimizer Control: @inline(always) & @specialized
    • New @inline(always) and @specialized attributes give you direct control over the compiler's inlining and generic specialization decisions.

    • 24:29 - Ownership System & Noncopyable Types
    • Equatable, Comparable, Hashable, and associated types now work with noncopyable and non-escapable types, broadening the ownership system's reach.

    • 26:18 - Iterable Protocol & Borrow/Mutate Accessors
    • A new Iterable protocol enables efficient borrow-based for loops over noncopyable elements, while new borrow and mutate accessors eliminate costly copies in computed properties.

    • 28:57 - New Standard Library Types: UniqueBox, UniqueArray, Ref
    • The standard library gains UniqueBox, UniqueArray, Continuation, and the new Ref/MutableRef types for safe, high-performance ownership patterns.

    • 31:11 - The Future of Swift
    • Highlights open-source progress including Swift Build, new workgroups for build, networking, Windows, and Android, and an invitation to participate at forums.swift.org.

Developer Footer

  • Videos
  • WWDC26
  • What’s new in Swift
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright Β© 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines