Swift Weekly Issue 35

insert image description here
insert image description here

foreword

This issue is the thirty-fifth issue of the weekly report organized by the Swift editorial team , and each module has been initially formed. If readers have good suggestions, welcome to leave a message at the end of the article.

Contributions or recommendations are welcome. It is currently planned to be released every two weeks on Monday, and like-minded friends are welcome to join in the weekly report compilation.

Standing on the pinnacle of life, laughing at the incompetence of death? Or kneeling on the edge of life, seeking the possibility of survival? The Swift community starts small and goes big!

Weekly Featured

News and Community: $200 Billion in Market Value Evaporated in Five Days, What Happened to Apple?

Proposal: with encoding validationString Initializers

Swift Forum: Distributed Tracing in Swift

Recommended blog post: iOS ReplayKit and Screen Recording

Topic Discussion:

Apple is considering raising the price of its high-end phones when it launches the new iPhone Pro this fall, so if the price of the new iPhone Pro in China exceeds 10,000 yuan by then, will you still buy it?

news and community

The market value evaporated 200 billion U.S. dollars in five days. What happened to Apple?

As recently as June, Apple became the first company to be valued at more than $3 trillion, but its latest quarterly earnings report raised concerns among investors about sluggish demand for its phones and other devices.

On August 4, Apple announced its third-quarter earnings. According to the financial report, Apple's revenue in the third fiscal quarter was US$81.797 billion, which was lower than the US$82.959 billion in the same period of the previous fiscal year, which was a sharp drop from US$94.836 billion in the previous quarter. After seeing the new quarterly financial report data, investors were surprised to find that the operating income of this giant listed company has declined for three consecutive quarters, and Apple predicted in the fourth quarter outlook that there will be little difference in the performance of the current quarter .

The company's share price fell one after another

The release date of Apple's third quarterly report is just before the launch of its new iPhone 15 series, but the market expects that the new model of Apple's mobile phone will not be as popular as before. Affected by pessimism, Apple's stock price fell 4.8% on August 4, the day when the financial report was announced, the largest single-day drop this year, and its market value evaporated by more than 160 billion US dollars in one day. Since then, Apple's stock price has not stopped the decline. As of Monday (August 7), Apple's stock price has suffered a "five consecutive declines". RMB 1.44 trillion.

Analysts at Bank of America said in an earnings report that Apple is facing a weakening environment in the U.S. smartphone market. In addition, overvaluation may also be another important reason for Apple's decline. Regarding the "three consecutive declines" in Apple's sales, Sun Yanbiao, president of the First Mobile Phone Industry Research Institute, said that the continued downturn in the consumer electronics market has weakened the demand for smartphones, and the lack of innovation is difficult to drive sales of new phones. Sales revenue continued to decline. If Apple's sales continue to decline year-over-year in the fiscal fourth quarter, it will be the longest period of year-over-year sales decline in the company's 20-year history. (Source: Financial Times)

Help customers with billing issues in your app

As we announced in April, soon, your customers will be able to settle payments directly in your app, making it easier to continue subscribing to your content, services, and premium features.

Beginning August 14, 2023, if an auto-renewing subscription cannot be renewed due to a billing issue, your app will display a provided form prompting the customer to update their Apple ID payment method. You can test this form first in the sandbox, and you can use the messages (English) and display (English) in StoreKit to delay or suppress the display of this form. This feature is available in iOS 16.4 and iPadOS 16.4 or later and requires no action to adopt.

List of APIs that require a reason statement is now available

Apple is committed to protecting user privacy on our platforms. We know that a small subset of APIs may be abused to gather data about users' devices through fingerprinting, a practice prohibited by our Developer Program License Agreement. To prevent misuse of these APIs, we announced at WWDC23 (in English) why developers need to declare the use of these APIs in the app's privacy checklist. This will help ensure that apps only use these APIs for their intended purposes. In this process, you need to select one or more approval reasons that accurately reflect how your app uses the corresponding API, and your app can only use the corresponding API for the reasons you choose.

Beginning in Fall 2023, if a new app or app update you upload to App Store Connect uses an API that requires a declared reason (including content from a third-party SDK), and you do not provide a reason for approval in the app's privacy checklist, Then you will be notified. Beginning Spring 2024, to upload new apps or app updates to App Store Connect, you will need to include a reason for approval in your app's privacy checklist to accurately reflect how your app uses the API.

If there is a use case for an API that requires a declared reason that isn't currently covered by the approved reason, and you believe it will directly benefit users of your app, please let us know.

suggestion

Proposal passed

SE-0403 Package Manager Mixed Language Target Support Proposal passed review. The proposal is detailed in the Proposals module under review in the thirty-fourth weekly report .

Proposals under review

SE-0405 String Initializers with Encoding Validation proposal is under review.

We propose to add new Stringfailables Initializerthat validate encoded input and return if the input contains any invalid elements nil.

Swift Forum

  1. Discusses Swift string comparison not equating ligatures to their components

About the content

I just found out that Swift Strings treats "office" and "office" as unequal, which surprises me because it treats "caña" and "caña" as equal (ie, both composed and decomposed forms). For the average user, these cases are equivalent - they just represent the same glyph differently (at least in some fonts).

I did some research and it seems this is because Swift promises to use "canonical" comparisons in Unicode terms, rather than "compatible" comparisons. The docs mention this, but don't explain what it means.

I looked further and found some controversies and history regarding ligatures in Unicode, which might shed some light on this (e.g. the current Unicode view on ligatures seems to be that they should not be used for kerning, such as "ffi", But it still contains some "inappropriate" ligatures - again, like "ffi" - which were added before this shift in mindset).

NSStringSimilarly, unless you compare(_:options:)select caseInsensitivethe option when using , in which case it treats the ligature as its exploded form. Which is weird because this has nothing to do with character case.

I'm guessing this post is mostly informational and warning to others. But I'm curious why Swift chose to do a "canonical" comparison instead of a "compatible" comparison? Also, there doesn't seem to be a way in the Swift standard library to perform a "compatibility" comparison - you have to import Foundation to get the string overlap in order to access the aforementioned NSStringmethods.

answer

Compatibility decomposition is a compromise that Unicode has to make when it needs to be compatible (as a superset) with earlier encodings. If these characters were proposed directly to Unicode, they would never be encoded. Usually, even if you're using them, you're probably doing something wrong, because what they encode (like ligatures) is not a property of the text, but of the display format.

In Unicode's point of view, they should not appear in raw strings by themselves. However, collapsing them into canonical form loses information about the format and thus cannot be safely applied to traditional texts where they are actually used. (In the case of "ff", not every pair of "f"s has to be joined in the display; those "f"s that span the two halves of the compound word should be kept separate. This distinction cannot be recovered by simply looking at the context, and needs to be done manually or This is done via a dictionary lookup.) This is fundamentally different from "ñ"-like canonical decompositions, which do not lose information during normalization.

If you want to know whether two strings are equivalent for compatibility, you can use Foundation's decomposedStringWithCompatibilityMappingmethod.

  1. Proposal for Swift Distributed Tracing

motivation

While Logging and Metrics can be used to instrument specific parts of an application, Distributed Tracing provides a holistic view of an entire distributed system. Together with these two, distributed tracing will complete the "three pillars of observability".

As with Logging and Metrics, the community will benefit most if a common API is used directly in libraries and frameworks to implement distributed tracing. End users should be free to choose a suitable backend implementation without changing the libraries or frameworks they are using.

suggested solution

Swift distributed tracing revolves around creating spans that together form a kind of tree structure. A trace can consist of spans recorded within a single service, or spread across multiple services. Swift Distributed Tracing uses the task-local Swift Service Context to achieve transparent propagation without manually passing the context.

Our proposed solution is a library for three "roles":

  • end user
  • Library and framework authors
  • Tracker backend implementation

user terminal

End users are the ones who benefit from distributed tracing. They choose a tracing backend that suits their needs, use a library with built-in support for distributed tracing in Swift, and do manual instrumentation in their own code.

Library and framework authors

Libraries/frameworks such as HTTP servers/clients, database libraries, etc. know best how to instrument the internals of their libraries. They use the Swift Distributed Tracing API for generic tracing support regardless of specific tracing backends.

example:

Tracking backend implementation

The last piece of the puzzle is the tracker backend implementation. They provide vendor-specific support for exporting trace spans.

example

Swift OTel exposes a tracker that exports to OpenTelemetry Collector . This has allowed adopters of this tracing library to export to popular OpenTelemetry-compatible backends such as Zipkin, Jaeger, Honeycomb, and others.

Reason for expiry

We propose that this package is at the "incubating" maturity level. We believe this package is an important building block for the server ecosystem, just as swift-log and swift-metrics are adopted by many server and client libraries .

The project has matured for over 3 years, has multiple active maintainers, and has met adoption requirements in a production environment.

  1. Discusses internal unwrapping of AttributedString index fetches resulting in nil values

Problem Description

I have a rich text string in which a substring is being replaced, but a fatalError is raised:

var string = AttributedString("café")
let replaceIndex = string.index(beforeCharacter: string.endIndex)
let range = replaceIndex..<string.endIndex
string.replaceSubrange(range, with: AttributedString("e"))
let next = string.index(afterCharacter: replaceIndex)
//                ^---- Unexpectedly found nil while unwrapping an Optional value
assert(next == string.endIndex)

This is surprising because I thought the index would be stable until the change. What's even more strange is that changing how the scope is created doesn't cause it to fail. The following code works fine:

var string = AttributedString("café")
let range = range(of: "é")!
string.replaceSubrange(range, with: AttributedString("e"))
let next = string.index(afterCharacter: replaceIndex)
assert(next == string.endIndex)

Using an ASCII character instead of the accent 'é' will not cause either range technique to fail. I've pored over the open source implementation to try to uncover where the nil optional values ​​come from, but I can't see anything wrong with it, which I don't think is the same as the currently released code.

Any suggestions on where my logic is going wrong?

I'm using macOS 13.4.1 and Xcode 15b5.

answer

To be clear, RangeReplaceableCollectionthe mutation operation of 's may invalidate existing indexes, since those indexes may contain information that is no longer valid for the mutated collection (for example, in the case of strings, computed byte offsets are no longer valid). From RangeReplaceableCollection.replaceSubrange(_:with:)the documentation it can be seen that:

Calling this method may invalidate any existing indexes used with this collection.

Also, this method is RangeReplaceableCollectionthe basis for almost all other operations on , so one should assume (unless otherwise stated for a particular type) that any mutating operation that might change information about an index will invalidate the existing index.

  1. Proposed access level for import statements

This is a proposal for better control over dependencies and imports in Swift. With this feature, imports can be marked as public (currently the way regular imports are), internal for implementation details of modules, and private or file-private for implementation details of source files.

Additionally, updated package access levels allow marking dependencies as visible only to modules within the same package. This is enforced like normal access levels in source files. Declarations that will be imported as internal can only be referenced from internal declarations or lower access levels, and will throw an error when used in public or package declarations.

Here's a typical use case, where dependencies are implementation details that we don't want exposed to clients in the module's API, and where diagnostics are expected:

internal import DatabaseAdapter

internal func internalFunc() -> DatabaseAdapter.Entry { ... } // Ok

public func publicFunc(entry: DatabaseAdapter.Entry) { ... }
// error: function cannot be declared public because its parameter uses an internal type

public func useInBody() {
    DatabaseAdapter.foo() // Ok
}

@inlinable
public func useInInlinableBody() {
    DatabaseAdapter.foo()
    // error: global function 'foo()' is internal and cannot be referenced from an '@inlinable' function
}

The proposal also defines a set of conditions under which dependencies can be hidden from clients. This provides a powerful way to completely hide implementation details and can speed up build times for clients.

This proposal aims to provide a formal and clearer alternative to replace @_implementationOnly. In contrast, this release provides familiar diagnostic information, more levels of control, and @testablebetter compatibility with non-resilient modules and clients.

Depending on the community's reaction to the proposed Swift 6 behavior, we may incorporate it into this proposal.

  1. Actors that discuss serialized file access

Problem Description

I'm wondering if using an Actor is a good option to protect a resource from concurrent access, for example a directory of files. In the past, I have used dispatch queues to achieve this. What are the pros and cons of using an Actor as a channel point to a blocking file access API?

answer

Just do typical CRUD operations on the file system

Actors can't help you here. Even outside of Actor reentrancy considerations, the order of execution of Actor methods called from outside the Actor is not guaranteed.

CRUD operations are already thread-safe (it would be a rather disappointing filesystem if they weren't). Actors are not needed since Actors do not "serialize" anything in the order in which the methods are executed.

What may be needed is a FIFO queue, and that's what the (serial) DispatchQueue solution provides for this.

Now, if you're talking about effectively "atomizing" a sequence of operations (e.g. not allowing concurrent mutations while enumerating a directory), then what needs to be protected is some mutable state, and an Actor can protect that. In my opinion, this is a higher level of abstraction than CRUD. In this regard, I think @terathe question of is more relevant here than might be thought.

  1. Discuss L-shaped enums

Problem Description

For lack of a better term, I have many "L-shaped" enums with some different payload types and some common payload types.

Here is an example:

extension ServerDelegate
{
    enum Request:Sendable
    {
        case get    (Get, EventLoopPromise<ServerResponse>)
        case post   (Post, EventLoopPromise<ServerResponse>)
        case delete (Delete, EventLoopPromise<ServerResponse>)
    }
}
extension ServerDelegate.Request
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

There is a problem with this layout:

It's hard to access common fields ( EventLoopPromise<ServerResponse>), unless you switch on the enum.

It's hard to switch on the actual variant payload, because you have to use _ to ignore common fields.

Here's an obvious refactoring that lifts the variant payload to another nested type:

extension ServerDelegate
{
    struct Request:Sendable
    {
        let operation:Operation
        let promise:EventLoopPromise<ServerResponse>
    }
}
extension ServerDelegate.Request
{
    enum Operation:Sendable
    {
        case get    (Get)
        case post   (Post)
        case delete (Delete)
    }
}
extension ServerDelegate.Request.Operation
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

But this feels like too much nesting and (too much?) type structure in direct proportion to the complexity I'm trying to model. Also ServerDelegate.Request.Operation.Get, ServerDelegate.Request.Operation.Postthe , etc. enumeration itself may have more nested structures.

What alternatives do we have? "

answer

The dots in the namespace are a result of nesting, which isn't really fundamentally related to the type structure here. It also seems reasonable to provide a convenience API to handle some .initcumbersome cases, such as:

extension Request {
    
    
  static func get(url: URL, params: [String: String], mintPromise: () -> EventLoopPromise) -> Self {
    
     ... }
}

Recommended blog post

iOS ReplayKit and Screen Recording

Abstract: This article mainly introduces the use of Apple's ReplayKit framework to realize the screen recording function, including in-app recording and system-level recording. ReplayKit was first offered in iOS 9 and has grown and enhanced many features. The article introduces in detail the creation and access of ReplayKit Extension, system-level recording process, and practical examples in LOOK live broadcast. However, screen recording development faces some challenges, such as memory constraints, development and debugging difficulties, memory control, etc. The article emphasizes careful handling of these issues during the development process, keeping memory usage away from the 50MB limit threshold, and making full use of logs to solve problems, so that the screen recording function can be completed gracefully.

TheRouter-iOS lightweight routing middleware

Abstract: TheRouter is a lightweight routing middleware created by Huo Lala, designed to support Android and iOS platforms. The middleware absorbs the features of other languages ​​on the iOS side, adds the annotation function, and strengthens the routing experience on the iOS side. TheRouter abandons the target-action or protocol concept of traditional iOS, and aligns with a wider range of background or Android applications. The main functions include dependency injection, hardcode elimination, dynamic capability and page navigation jump capability. The article explains in detail the implementation principles of TheRouter, such as annotation-style dependency injection, path hard-coding processing, etc., and provides detailed usage introduction and examples.

iOS App Store listing rejected case

Abstract: This article mainly records some rejected cases encountered in the App Store listing process, as well as the corresponding cause analysis and solution strategies. Cases cover issues at different stages, from functional integrity, information needs, and privacy affirmations, to software requirements and upload rejections. The article also elaborates on the causes of various problems, such as incomplete APP functions, integration of unused libraries, incomplete filling of private information, etc., and proposes corresponding solutions. Through the sharing of these cases, developers can understand and learn how to avoid similar mistakes and complete the App Store listing process more smoothly.

topic discussion

According to reports, the once-popular children's programming training now has hidden dangers of thunderstorms. Do you think it is necessary for children to be exposed to programming classes early?

  1. Necessary: ​​Coding classes can stimulate children's creativity and develop problem-solving skills.
  2. Unnecessary: ​​Lacking foundation and maturity, programming requires math and logical thinking skills, leading to difficulty understanding and frustration.
  3. It varies from person to person: some children are suitable for early exposure, gifted and enthusiastic, fulfilling their potential, others can be considered at a later stage.

Welcome to leave a message at the end of the article to participate in the discussion.

about Us

The Swift community is a non-profit organization jointly maintained by Swift enthusiasts. We mainly operate the WeChat public account in China. We will share technical content centered on Swift combat , SwiftUl , and Swift foundation , and also organize and collect excellent learning materials.

Special thanks to every editor in the Swift community editorial department, thank you for your hard work, provide high-quality content for the Swift community, and contribute to the development of the Swift language.

Guess you like

Origin blog.csdn.net/qq_36478920/article/details/132423063