WWDC Quick Look 💓 By SwiftGGTeam
What's new in Foundation

What's new in Foundation

Watch original video

Highlight

Foundation introduces Swift’s native AttributedString and new formatting API in iOS 15 and macOS Monterey (.formatted()) and an automatic syntax consistency engine that greatly simplifies internationalization, localization, and rich text processing.

Core Content

The Dilemma of Rich Text Processing

The Foundation framework provides basic functions for all apps and frameworks, of which internationalization/localization is required by every app.This year marks Foundation’s biggest update ever in terms of internationalization.

Rich text processing has always been a pain point in iOS development.NSAttributedStringIt is a reference type, not Swift’s native value type.It is inconsistent with Swift String’s character counting behavior and does not support localization.Developers need to manually handle complex range calculations, which are prone to errors.

AttributedString: Swift native rich text

(02:05) iOS 15 introduces newAttributedStringStructures, designed specifically for Swift:

  • Value type: can be safely copied, passed, and stored as attributes
  • Consistent character count: Uses the same character count logic as Swift String
  • Native Localization: Full support for localized strings
  • Type safety: properties use the correct type (such as SwiftUI’s Font)
  • Codable support: can be safely serialized and deserialized

Refactoring of formatting API

(17:28) OldDateFormatterNumberFormatterClasses are relatively heavyweight and require creating instances, configuring styles, and handling threading issues.New API calls directly on types.formatted()Method, concise and thread-safe.

Automatic syntax consistency engine

(29:41) One of the most troublesome issues in multi-language applications is syntax consistency.For example, if the user selects “2 large salads” in the English interface, when switching to Spanish, “2 ensaladas grandes” should be displayed instead of “2 grandes ensaladas”.It used to be necessary to prepare multiple versions of strings for each language.

New automatic syntax consistency engine passedinflect: trueParameters handle these issues automatically.

Detailed Content

AttributedString Basics

(02:50) Create an AttributedString and set the attributes:

func attributedStringBasics(important: Bool) {
    var thanks = AttributedString("Thank you!")
    thanks.font = .body.bold()

    var website = AttributedString("Please visit our website.")
    website.font = .body.italic()
    website.link = URL(string: "http://www.example.com")

    var container = AttributeContainer()
    if important {
        container.foregroundColor = .red
        container.underlineColor = .primary
    } else {
        container.foregroundColor = .primary
    }

    thanks.mergeAttributes(container)
    website.mergeAttributes(container)

    print(thanks)
    print(website)
}

Key points:

  • AttributedStringIt is a structure and needs to be usedvarModification can modify attributes
  • Properties are set directly on the instance, such asfontlinkforegroundColor
  • AttributeContainerIs a collection of attributes that can be merged into strings in batches
  • mergeAttributesWill merge all properties of the container into the target string

Create AttributedString from Markdown

(07:29) Use the localized parameter to create localized AttributedStrings from Markdown:

func prompt(for document: String) -> String {
    String(localized: "Would you like to save the document "\(document)"?")
}

func attributedPrompt(for document: String) -> AttributedString {
    AttributedString(localized: "Would you like to save the document "\(document)"?")
}

Key points:

  • AttributedString(localized:)Will parse Markdown format (bold, italics, links)
  • Interpolation\()Correct placement of localization parameters is automatically handled
  • Markdown syntax_means italics,**means bold,[text](url)Represents a link

Custom Markdown properties

(10:42) Custom properties can be defined and set via Markdown syntax:

enum RainbowAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
    enum Value : String, Codable {
        case plain
        case fun
        case extreme
    }

    public static var name = "rainbow"
}

Markdown syntax^[an attribute](rainbow: 'extreme')Will be parsed as a custom attribute.

Key points:

  • CodableAttributedStringKeyProtocol enables properties to be serialized
  • MarkdownDecodableAttributedStringKeyProtocol makes properties parsable from Markdown
  • ^[text](key: 'value')Is the Markdown syntax for custom attributes

Date formatting

(17:28) New.formatted()The API makes date formatting extremely easy:

func formattingDates() {
    let date = Date.now

    let formatted = date.formatted()
    // example: "6/7/2021, 9:42 AM"

    let onlyDate = date.formatted(date: .numeric, time: .omitted)
    // example: "6/7/2021"

    let onlyTime = date.formatted(date: .omitted, time: .shortened)
    // example: "9:42 AM"
}

Key points:

  • formatted()Automatically format using the current locale
  • .numeric.omitted.shortenedSimplify configuration with predefined styles
  • Thread safe, no need to create formatter instance

Complex date format

(18:36) Use the Fluent API to build complex formats:

func formattingDatesMoreExamples() {
    let date = Date.now

    let formatted = date.formatted(.dateTime.year().day().month())
    // example: "Jun 7, 2021"

    let formattedWide = date.formatted(.dateTime.year().day().month(.wide))
    // example: "June 7, 2021"

    let logFormat = date.formatted(.iso8601)
    // example: "20210607T164200Z"

    let fileNameFormat = date.formatted(.iso8601.year().month().day().dateSeparator(.dash))
    // example: "2021-06-07"
}

Key points:

  • .dateTimeStart building the format and chain calling.year().month()etc.
  • .wide.numericand other parameters to control the style of each part
  • .iso8601Provides standardized date format

Date range formatting

(20:30) Format date range:

func formattingIntervals() {
    let now = Date.now
    let later = now + TimeInterval(5000)

    let range = (now..<later).formatted()
    // example: "6/7/21, 9:42 – 11:05 AM"

    let timeDuration = (now..<later).formatted(.timeDuration)
    // example: "1:23:20"

    let components = (now..<later).formatted(.components(style: .wide))
    // example: "1 hour, 23 minutes, 20 seconds"

    let relative = later.formatted(.relative(presentation: .named, unitsStyle: .wide))
    // example: "in 1 hour"
}

Key points:

  • The date range will intelligently merge the same parts (such as month, day, and year are only displayed once)
  • .timeDurationDisplay duration length
  • .componentsShow component breakdown
  • .relativeShow relative time description

Number formatting

(25:30) Number formatting is equally concise:

func formattingNumbersWithStyles() {
    let percent = 25
    let percentFormatted = percent.formatted(.percent)
    // percentFormatted is "25%"

    let scientific = 42e9
    let scientificFormatted = scientific.formatted(.number.notation(.scientific))
    // scientificFormatted is "4.2E10"

    let price = 29
    let priceFormatted = price.formatted(.currency(code: "usd"))
    // priceFormatted is "$29.00"
}

Key points:

  • .percent.currency.number.notationWait for predefined styles
  • Automatically handle locale-related formats (such as currency symbol position)
  • Thread safe, no need to create formatter instance

SwiftUI TextField integration

(26:05) SwiftUI TextField directly supports formatting:

struct ReceiptTipView: View {
    @State var tip = 0.15

    var body: some View {
        HStack {
            Text("Tip")
            Spacer()
            TextField("Amount",
                      value: $tip,
                      format: .percent)
        }
    }
}

Key points:

  • TextFieldformatParameters directly accept formatting styles
  • .percentAutomatically handles percent sign input and display -Bound values ​​remain as numeric types, no manual conversion is required

Automatic syntax consistency

29:41inflect: trueThe automatic parameter processing syntax is consistent:

func addToOrderEnglish() {
    let quantity = 2
    let size = "large"
    let food = "salad"

    let message = AttributedString(localized: "Add ^[\(quantity) \(size) \(food)](inflect: true) to your order")
    print(message)
}

Key points:

  • ^[...](inflect: true)Markup requires syntactically consistent text
  • The system will automatically adjust the order and form of words according to the current language
  • Supports consistent grammar for numerals, adjectives, and nouns

Core Takeaways

  • Replace NSAttributedString with AttributedString: Use it directly in new projectsAttributedString, which automatically handles localization and Markdown parsing.When used with SwiftUI’s Text view, no bridging is required.

  • Replace Formatter class with .formatted(): Use new ones for date, number, currency formatting.formatted()API.The code is simpler, there is no need to consider thread safety and instance management, and the performance is better.

  • Use Markdown to define localized strings: in.stringsUse Markdown syntax (bold, italics, links) directly in the file,AttributedString(localized:)will be parsed automatically.This reduces formatting logic in the code.

  • Reduce translation effort with automatic syntax consistency: Used in multilingual appsinflect: trueParameters to allow the system to automatically process the grammatical consistency of numerals and adjectives.This can significantly reduce the number of string variations that need to be translated.

  • TextField directly binds numeric types: Using TextField in SwiftUIformatParameters are bound to numeric values ​​instead of manually handling string conversions..percent.currencyand other styles available out of the box.

Comments

GitHub Issues · utterances