Author: leejunhui, iOS & RN developer. Working for Ladder Technology, responsible for cross-platform application development

Review: Guo Peng, editor of veteran driver Technology Weekly, working in Dingxiang Garden, development of Dingxiang Mother App

This paper is based on WWDC21-What’s New in Foundation

The introduction

As described on WwDC21-What’s New in Foundation, the iOS and macOS underlying system core library Foundation comes with the following updates:

  • FoundationThe latest features in your app will help you improve your applicationlocalizationandinternationalizationSupport.
  • Apple is designed forSwiftCreates a new string typeAttributedStringAnd you can use it nowMarkdownTo apply styles to localized strings.
  • The new syntax protocol engine automatically fixes localized strings to match syntactic and complex numbers.
  • This update brings date and number formatting improvements to simplify previously complex processes while also further improving performance.

AttributedString – AttributedString

AttributedString in iOS, which is familiar to most developers, consists of three parts:

  • The Characters of Characters
  • Interval Ranges
  • Dictionary is the Dictionary

AttributedString allows you to associate attributes (key-value pairs) with a specific range of strings. The most common string attributes are defined by the SDK, but you can create your own.

When the Foundation framework came out, the NSAttributedString was introduced along with it. This year, Apple released an entirely new construct, AttributedString, based on the modern Swift language features.

1.1 AttributedString first

AttributedString has the following properties:

  • Value type, starting from scratchSwiftbuild
  • withSwiftThe string has the same character counting behavior
  • Can be localized
  • AttributedStringBuilt with security and assurance in mind (this includes compile-time security with strong typing as well as usageCodableSecurity during decompression)

1.2 AttributedString base

In the screenshot above, some of the text is bold, some is italic, and some is clickable with links. So how to pass the brand newAttributedStringTo implement it?

  • First get one by simple initialization syntaxAttributedStringStruct, and the initialization passed in isThank you.

At the same time, what we have here isAttributedStringSet up aSwiftUIFont propertiesbold“Will make the font bold. It is worth noting that this property works onAttributedStringGlobal scope.

  • Again, we initialize one againAttributedStringStruct, and the initialization passed in isPlease visit our website. Here we set the font to italicitalic. At the same time set upAttributedStringlinkThe property is aURL.

  • AttributeContainerStructs are a very useful tool that can be independent of a specific string and hold properties related to the string. Here we set different properties depending on the importance of the text.

  • Finally, by callingmergeAttributesMethods,containerThe properties carried by the object are applied tothankswebsiteOn.

As we said earlier, an AttributedString is made up of characters, intervals, and a dictionary of attributes. But if you want to access all three parts of an AttributedString, it’s not directly through the AttributedString itself, it’s through the View.

1.3 AttributedString View

The AttributedString View consists of two parts:

  • Characters character, used to access strings
  • Runs is used to access attributes

View is a Collection type for Swift, which means we can manipulate the View as if it were an Array type.

1.3.1 Characters View

Now suppose the designer asks us to implement an orange text color for punctuation:

We can do this with the following code:

  • First of all bycharactersRemove the characterView
  • It then iterates through the charactersView, and through theisPunctuationFilter characterViewThe characters in the collection that are punctuation marks
    • Finally, use the interval operator to determine the interval of the punctuation character, and then set its color to orange

1.3.2 Runs the View

A Run View contains the starting position, length, and value of a particular property.

The string above consists of four Run Views. Thank you! , Please visit our website,.

As shown in the code above, we can get how many Run Views there are by counting under the runs attribute of the AttributedString. The character and Run View ranges are interchangeable, so you can access the string contents of a range by subscripting.

For a Run View, focusing on a particular property might be more useful.

In the above code, we used link’s key path to merge link attributes. If we just focus on link properties, we have three Run Views. Traversing the Run View yields a tuple of (value, range). Because value is type-safe, we can use an API like Scheme that exists on the URL. Check for strings that do not start with HTTPS and add them to the insecureLinks array if a match is successful.

1.4 AttributedString use

Another useful scenario is inAttributedStringTo find a specific substring, after the successful search can edit the corresponding range of string content and string attributes. Let’s say we want to putvisitChange it to something more retrosurf, as shown in the figure below:All we need is the following code:

1.5 Localization of AttributedString

SwiftIn theAttributedStringAs well asObjective-CIn theNSAttributedStringAll now support localization. In the localized scenario,AttributedStringJust like a normal string in your App’s string file. inSwiftIn, interpolation pairs by string are now supportedStringAttributedStringDo the local formatting, likeSwiftUIIn thetext viewThe same.As shown in the code above:

  • promptMethod takes a string argumentdocumentAnd returns a localized string. Do not need to pass the string formatting function and use% @%dAnd so on, you just need to pass in the specific value.
  • attributePromptSame as above.

Xcode can generate string files automatically from the Compiler by enabling the Use Compiler to Extract Swift Strings option in the Localization setting under the Build Settings.

1.6 AttributedString & Markdown

AttributedStringsupportMarkdownSyntax, here’s oneSwiftUITextComponents use localizedAttributedStringExample:

  • Through theThank youInsert two asterisks on both sides, and the live preview area on the right shows the effect of bold.

  • By inserting underscores around the Text, the Text component receives it and renders it in italics.

  • In addition, supportMarkdownLink syntax, that is, can provide different syntax for different languagesURL.

Strikeout and block syntax in Markdown are also supported.

1.7 AttributedString conversion operations

To archive AttributedString, we need to be able to convert between the AttributedString and NSAttributedString reference types. The AttributedString is probably part of your data model, so we need to be able to serialize and deserialize it. Finally, we want to be able to set custom string properties in Markdown.

Each of the above three scenarios involves an AttributedString conversion operation, which we examine in turn.

1.7.1 Converting a structure type to a class type

All you need to do is pass the AttribuedString into the constructor of NSAttributedString, and leave it up to the SDK to associate the attributes.

1.7.2 Serialization and deserialization

Because AttribuedString has a default Codable implementation, the Receipt structure here only needs to follow the Codable protocol.

So how do you serialize and deserialize custom string attributes? We can take a closer look at attributes. An attribute consists of two parts: a key and a value. Key is a type that follows the AttributedStringKey protocol and defines what type of value is required and the attribute name for archiving. Key can also follow other protocols to customize the serialization and deserialization of value.

As the code above shows, AttributedStringKey only needs to define the association type Value and the static variable name. Now suppose we want this RainbowAttribute attribute Codable.

Codable is a type alias in the Swift standard library that stands for Decodable and Encodable protocols.

Just like the above code, let properties follow CodableAttributedStringKey agreement, The type of the agreement the same DecodableAttributedStringKey and EncodableAttributedStringKey alias. Also, make the Value type follow the Codable protocol.

And if you want to the properties of the above is part of our localized string of words, you just need to follow a MarkdownDecodableAttributedStringKey agreement.

Declare a follow MarkdownDecodableAttributedStringKey AttributedString attribute of the agreement, and then let the attribute value of follow Codable agreement, We can implement the effect of a rich text string in Markdown text, as shown in the following figure.

The first two lines in the figure above are very common in Markdown, with the description text in brackets and the actual URL in brackets. To render the image with an exclamation mark prefix, render a link without an exclamation mark prefix. The third line shows the syntax for custom attributes.

A custom property starts with ^, then a bracket to receive text, and finally a bracket to represent the property. Properties are represented in JSON5 format.

JSON5 is compatible with JSON and allows keys without quotes, comments, and a few other features.

Json-related apis in Foundation have also been added to support JSON5.

Because custom properties are represented via JSON, anything that can be deserialized by JSONDecoder is automatically compatible with the new custom Markdown syntax.

In the code above, the first line contains one custom property, the second line contains two custom properties, and the third line contains one property with multiple child properties.

1.8 AttributedString Scopes

Scopes are a collection of property keys. Scopes are useful in deserializing JSON or Markdown because they tell us what properties we want to look for and how to deserialize them.

Apple has defined their respective scopes for Foundation, UIKit, AppKit and SwiftUI. You can define scopes for your own application.

  • As shown in the code above, we are inAttributeScopesextensionA structure is declared inCaffeAppAtrributesThe structure followsAttributeScopeThe agreement. A custom property is then declaredRainbowAttribute“And declare aSwiftUIAttributesThis will allow us to use itSwiftUIAll attributes inside. And because thescopeRecursive nesting is supported, so it is also included by defaultFoundationCustom property of.
  • In our newscopeIt is useful to define an attribute in thescopeUsed in a function as an argumentkey pathSyntax.

  • Finally, we can start from custommarkdownOur localization string has been loaded in.

As shown in the figure above, after the Markdown in the localized font file is converted to an AttributedString, the application finds the range for which the attribute needs to be set and applies the attribute to the string for that range. And since the attributes come from localized font files, this applies to all languages.

Second, Formatters

There are new apis for Formatters, another long-standing feature of the Foundation framework, which take data like numbers, dates, and times and convert them into localized, user-readable strings. Caching and reusing Formatters has become a common pattern because Formatters are underwritten by a considerable amount of configuration data. But it is not always appropriate to share the same Formatter between many different codes. This year, Apple redesigned the Formatter-related apis to improve performance and usability. In short, the new Formatters API focuses on “formatting.”

With the sample code above, we can see what “cache mode” looks like when the formatter uses it. This usually consists of two parts:

  • Create and configure oneFormatter
  • To pass toFormatterA date that returns a string

2.1 newFormattersgrammar

So can we simplify the above steps? Formatted formatted object (formatted object). Formatted object (formatted object) Formatted object (formatted object) Formatted object (formatted object) Formatted object (formatted object) Formatted object (formatted object) Formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object (formatted object) formatted object And specify what the formatting criteria are. It takes only one line of code to complete the above two steps.

After the contents of a dateLabel are converted via the new Formatters API, we can look at the magnitudeLabel content below. It may seem like a single line of code to format a floating-point number to a string, but the conversion hides some complexity and has some notable pitfalls that can lead to completely wrong results. The reader needs to pay special attention to string constant modifiers when converting floating point numbers to strings.

In contrast, the new API above is easier to understand, more readable, and more maintainable. Declare how we want magnitude to be formatted as a string by using the normal functions in Swift. At the same time, the new API can implement code completion and type safety.

Apple will apply the new Formatters API to all ten Formatters in Foundation, including cleaning and simplifying interfaces, refactoring underlying code to avoid common errors, and adding a host of new features.

Next, we’ll dive into two of the most common formatting scenarios: dates and numbers.

2.2 Date Formatting

Date formatting is essentially the conversion of an absolute point in time into a date as we humans understand it, which involves “calendars” and “time zones”. Even more important, take into account that people in different regions have different preferences for displaying dates, a preference commonly known as a “locale.” Let’s take a look at the simplest date formatting code.

  • First of all, throughDate.nowGets the current point in timedate
  • Then, in thedateObjectformattedMethod to get the formatted contentformatted

The default date formatting is that simple, and of course, as you can see in the example above, date formatting supports a variety of configurations.

  • You can configure it to display only the date or only the time.

An important goal of the new Formatters API is to provide as much compile-time support as possible when creating proper formatting. Formatting with magic strings creates traps that look correct in normal cases, but produce completely wrong values in extreme cases. Let’s say we get the last day of the year.

  • By specifyingformattedFunction to obtain time representations in different formats. The code above indicates the need to display the year, month and day information through a chain call. The final result will be based on the user’s localelocaleOutput the corresponding content.

  • Of course, year (year()), month (month()), Japan (day()) and week (weekday()) functions are configurable, the above code by configuring the month parameter iswide“To output the full representation of the month and week.

  • In addition to the regular display mode, the newFormatters APIIt also supports outputISO 8601Format time stamp, and on this basis can be implemented to display only year month day, and then specify the specific delimiter between year month day.

There may be more than one style for each type. For dates, there are dateTime and ISO 8601 display styles. Styles can be used for default configuration or customization.

  • Formatting aboveAPIFields need to be specified (Fields) list, some of which have additional options.
  • The order in which the developer provides these fields doesn’t matter; each field simply tells the formatter what values to include in the final output.
  • AppleFor formattingAPIProvides the most useful default implementation with no default parameters or just a style name.
  • Once you start adding fields, the output will be custom and reflect only what you choose to display, sort of likeUIPlaceholder text in.

This update also provides a new API for formatting two dates associated with each other.

  • The first is formatted with the range operator between the two dates, and the result is a time interval.
  • A time interval can display only the time and no date, just as you would format a single date.
  • You can also format the time interval as a duration (timeDuration), can be formatted as a component (components), or a relative time.

2.2.1 Formatting AttributedString

Another new feature of Formatters is formatting AttributedString. With the new AttributedString structure and Formatters API, you can format the output of AttributedString anywhere. In watchOS, a lot of complications are formatted strings, and because Apple Watch is a very personalized device, it is important to take into account the user’s preferences. Here is a SwiftUI demo, we can find out.

Pictured above is the starting point for Caffe Companion, which shows you your next free cup of coffee. There is a SwiftUI view that is only used to display a formatted date string. SwiftUI Preview allows you to adjust different locales to preview different effects by setting the locale parameter in the date formatter.

  • In order to achieve the custom time display effect, we added some time formatting fields to achieve the effect of only showing minutes, hours, and weeks. Then in order to achieve the effect of making the week part orange, I need to set thestrconvertAttributedString.
  • Then throughAttributeContainerSpecify the range of the style to be replaced as week, specify the color as orange, and finally callreplaceAttributesMethod implementation is shown on the rightApple WatchThe effect of.

By adding different locales to SwiftUI Preview, we can test that in different locales, the week is displayed in different positions, but eventually orange is added correctly.

2.2.2 Converting a String to a date

Everything above is converted from a date to a string, so let’s talk about the conversion from a string to a date scenario.

  • As shown in the code above,DateObject initializer adds a new parameterstrategy, the strategy for initializing the date object. So the strategy we passed in here is oneformatObject that contains the year, month and day. At the same time,formattedThe string is created bydateObject formatted. This applies to an input field that can either allow the user to enter a new date or display the output.
  • The above conversion may fail because the input could causeDateObject failed to initialize, so addtry?.

  • As shown in the figure above, some formatting strategies have more advanced parsing options. Here we parse a fixed format, which is useful for formatting the time received from the server.
  • Initializes a date resolution policy, the incoming formatted string is concatenated by string interpolation, and has code completion, compared to specifying such asYYYY-MM-DDThis kind of “magic” string is much simpler and more intuitive. So from now on, when formatting a string as a date, you don’t have to worry about how many uppercase values you should useY.

2.3 Number Formatting

Number formatting is the process of converting an integer or floating-point number into something that a person can read.

  • In contrast to date formatting, getting the result is simple and does not require passing in additional parameters.

  • As shown in the figure above, number formatting supports a variety of configurations. We can configure the output to be a string in percentage format, or a string in scientific notation format, or to output the content in comparison format.

  • Finally, the formatting of collections now only requires formatting the corresponding arrays. As shown above,memberStyleThe parameter declares the formatting style of each element in the array. The output is correct for different user locales.

SwiftUI supports content formatting styles on TextFeild, and since formatting styles have the type of content that needs to be formatted, we can use a readable but safe syntax to format tips.

  • As shown in the figure above, we used set formatting in the raw material part, currency formatting in the price part, number formatting in the quantity part, and localized operation on the order quantity button.

2.4 Internationalization and localization of strings and formatters

More on internationalization and localization of strings and formatters can be found in the other WWDC sessions: Localize Your SwiftUI App & Streamline Your Strings

Grammar Agreement

Finally, let’s look at an entirely new feature — Automatic Grammar Agreement. Previously, languages like Spanish were limited in their ability to localize expressions of natural translation, sometimes leading to awkward conversations. These languages require transformations to achieve agreement between tense and plural in different conversations, and sometimes even to know the user’s preferred address. The same is true of English, which has both singular and plural nouns.

3.1 Automatic Grammar Agreement

We’ve discussed some terms in the language, but let’s dig deeper with practical examples.

In Caffe, you can order a meal and set the size and quantity of the meal. Let’s start with a salad.

Then our friend said she needed one too, so we upped the number to two. In English, the word salad changes its singular or plural form to match two salads. This is called a grammatical agreement. This means that all the words in the sentence must match each other. It is a common grammatical protocol in English to correct words for plural problems. Now switch our App to Spanish.

Here we have an Ensalada pequena, or a small salad. When we order another one for a friend, the order confirmation button needs to be pluralized the same way it is in English, but with one difference. In Spanish, adjectives like “small” and nouns like “salad” need to agree with a specific amount.

So the order confirmation button says Ensaladas Pequenas instead of Ensalada Pequena.

Next, we focus on drinks. As shown in the figure above, for the words in the order button, it is necessary not only to match the singular and plural numbers correctly, but also to reach agreement on the morphology of these words. Juice and Jugo are masculine. And the adjective pequeno “small” must also be matched. To properly internationalize and localize these literals, we end up with the problem of “combinatorial explosion.” Each combination of food, size, and quantity requires a different localized string. At the code level, the following scenario occurs.

We need to switch each item, and we also need to determine the size of the selection, and so on. You also need a string file to properly pluralize the counts in each string. Now, by using the same technology that prompts users for input on the system keyboard, Apple has created a new API that can easily handle the problem. This feature is named automatic syntax protocol because the system automatically fixes localized strings so that they have correct syntax.

3.2 Automatic Grammar Agreement

With the new Automatic Grammar Agreement, the code is much simpler. You can specify the amount, size, and specific meal in a single string. The Autogrammar association automatically fixes the syntax by “reflection”. Let’s break it down step by step. In order to perform the “reflection” process, we need to know which parts of the string need to be automatically syntactic fixed. Fortunately, in Swift there is an entirely new type, AttributedString AttributedString, and the ability to set custom attributes in Markdown. When we export the localization of the Caffe project, we get a string file containing our prompt text and localized strings in our code, such as the name and size of the meal.

In the Latin American Spanish context, the localizer uses a rearrangement syntax to switch the size and order of meals because Spanish adjectives such as “small” or “large” come after nouns. Some languages have consistency not only in the localized text itself, but also between the text and the person reading it. Automatic syntax protocols also help solve this problem.

For example, as you can see above, the memo app on iOS pops up a welcome menu when you first use it. In English, Welcome is Welcome to Notes. In Spanish, Te Damos la Bienvenida a Notas, we welcome you to use the memo. We want to have the same Spanish experience as English. In Spanish, however, the word bienvenido must match the user’s preferred title. The title can be one of several options that change the content of the text. Using the right title can lead to a more personal and inclusive experience.

In this year’s update, Apple created a title entry for Spanish-speaking users. In the language and region Settings, there will be a new title option.

As shown in the image above, users can choose to set different titles and choose whether to share this setting with all apps.

Above is the new memo welcome screen after the user has set a female title.

The above is the memo welcome screen with the male title set. If we don’t know if the user has set a name, we’ll use the original string as an alternative. This year, Apple introduced automatic syntax protocols for Spanish and English. Just like the welcome interface for memos, you can apply the same techniques to your own applications.

Four,

Foundation has a lot of great new features this year that you can use in your app starting today.

  • AttributedStringProvides a fast, easy to use andSwiftPriority interface to add key-value pairs in a string range to achieve rich text effect. You can be inSwiftUIThe use ofTextComponent and used in localized stringsMarkdownSyntax.
  • New formatterAPIThe focus on formatting simplifies code and improves performance.
  • Finally, the automatic syntax protocol intelligently fixes localized strings to match syntactic tenses, singular and plural numbers, and the user’s own appellation Settings.

Pay attention to our

We are the Veteran Driver Tech Weekly, a tech newsletter that continues to pursue premium iOS content. Welcome to follow.

Focus on politeness, focus on[Old Driver Technology Weekly], reply “2021” and get the internal reference of 2017/2018/2019/2020

Support the author

I recommend the WWDC21 Insider column, which contains 102 articles about WWDC21 and is the source of this article. If you are interested in the rest of the content, please click the link to read more

WWDC internal reference series is led by the old driver organization of high-quality original content series. We’ve been doing it for a couple of years, and it’s been good. It is mainly for the annual WWDC content, do a selection, and call on a group of front-line Internet iOS developers, combined with their actual development experience, Apple documents and video content to do a second creation.