根据 Apple 开发者官网 WWDC21 - What's new in Foundation[2] 上的描述,iOS
以及 macOS
底层的系统核心库 Foundation
带来了如下更新:
Foundation
的最新特性能够帮助你改进应用的本地化和国际化支持。Swift
打造了一个新的字符串类型 AttributedString
,同时你现在可以使用 Markdown
来将样式应用于本地化的字符串上。iOS
中的 AttributedString
相信大多数开发者都不会陌生,它由以下三部分组成:
AttributedString
允许您将属性(键值对)与字符串的特定范围相关联,最常见的字符串属性由 SDK 进行定义,但是你可以创建属于你自己的属性。
在 Foundation
框架面世之时,NSAttributedString
类型便随之一起推出。而今年,Apple 推出了一个基于现代化的 Swift
语言特性的全新的结构体 - AttributedString
。
AttributedString
有以下特性:
Swift
构建Swift
的字符串有相同字符计数行为AttributedString
的构建考虑到了安全性与保障性(这包括具有强类型的编译时安全性以及使用 Codable
解压缩期间的安全性)
上面的截图中,有文字被加粗,也有文字是斜体,还有带链接可点击的文字。那么如何通过全新的 AttributedString
来实现呢?
AttributedString
结构体,传入的初始化内容是 Thank you
。同时,我们这里对 AttributedString
设置一个的 SwiftUI
字体属性 bold
,设置之后会让字体有加粗的效果。值得注意的是,该属性作用在 AttributedString
全局范围内。
AttributedString
结构体,传入的初始化内容是 Please visit our website
。这里我们设置字体为斜体 italic
。同时设置 AttributedString
的 link
属性为一个 URL
。AttributeContainer
结构体是一个十分有用的工具,它可以不依赖具体的字符串并同时保存字符串的相关属性。这里我们根据文本的重要性不同设置了不同的属性。mergeAttributes
方法,将 container
对象所携带的属性应用在 thanks
和 website
上。我们前面说到过,AttributedString
是由字符,区间以及属性字典三大部分组成的。但是如果需要访问一个 AttributedString
的这三大部分内容并不是直接通过 AttributedString
本身,而是通过 View
。
AttributedString
的 View
由下列两部分组成:
View
是 Swift
的 Collection
类型,那么也就是说我们可以像操作 Array
类型一样来操作 View
。
现在假设设计师要求我们实现标点符号的文字颜色为橘色:
那么我们可以通过以下代码来实现:
characters
取出字符 View
View
,并通过 isPunctuation
筛选出字符 View
集合中为标点符号的字符一个 Run View
包含了一个特定的属性的起始位置、长度、以及具体的属性值。
上面的字符串由 4 个 Run View
组成。分别是 Thank you!
、Please visit our
、website
、 .
。
如上代码所示,我们可以通过 AttributedString
的 runs
属性下面的 count
来获取有多少个 Run View
。character
和 Run View
的区间是可以相互转换的,所以你可以通过下标访问到某个区间的字符串内容。
对于 Run View
来说,专注于一个特定的属性这种场景可能更加有用。
上面的代码中,我们使用了 link
的 key path
来合并链接属性。如果我们只关注链接属性的话,我们这里有三个 Run View
。遍历 Run View
会得到一个 (value, range)
的元组。因为 value
是类型安全的,所以我们可以使用存在于 URL
上的 scheme
这样的 API
。上面的代码表达意思就是检查开头不为 https
的字符串,匹配成功则加入 insecureLinks
数组中。
另外一个有用的场景是在 AttributedString
中查找特定的子串,查找成功后可以编辑对应区间内的字符串内容以及字符串属性。比如我们想把 visit
改成更为复古的 surf
,如下图所示:
我们只需要下方代码即可实现:
Swift
中的 AttributedString
以及 Objective-C
中的 NSAttributedString
现在都已支持本地化。在本地化的场景下,AttributedString
就像普通的字符串一样位于你的 App 的字符串文件中。在 Swift
中,现在支持通过字符串插值对 String
和 AttributedString
进行本地化的格式化工作,就像 SwiftUI
中的 text view
一样。
如上图代码所示:
prompt
方法接收一个字符串参数 document
并返回一个本地化之后的字符串。不需要通过字符串格式化函数并使用 %@
或 %d
等格式化说明符,你只需要直接传入具体的值即可。attributePrompt
同上。
Xcode
可以通过编译器自动生成字符串文件,只需要开启位于Build Settings
下的Localization
设置中的Use Compiler to Extract Swift Strings
选项。
AttributedString
支持 Markdown
语法,下面是一个 SwiftUI
中 Text
组件使用本地化的 AttributedString
的例子:
Thank you
两侧插入两个星号,右侧的实时预览区域就直观的显示出了加粗的效果。Markdown
中链接的语法,也就是说 可以为不同的语言提供不同的 URL
。
Markdown
中的删除线以及代码块语法也得到了支持。
要对 AttributedString
进行归档,我们需要能够在 AttributedString
与 NSAttributedString
这一引用类型之间进行相互转换。AttributedString
有可能是你的数据 model
中的一部分,因此,我们需要能够对其进行序列化和反序列化。
最后,我们希望能够在 Markdown
中设置自定义的字符串属性。
上述三种场景都涉及到了 AttributedString
的转换操作,我们依次进行分析。
只需要将 AttribuedString
传入 NSAttributedString
的构造方法中即可,至于属性如何关联则交给 SDK 完成。
因为 AttribuedString
有默认的 Codable
实现,这里的 Receipt
结构体只需要遵循 Codable
协议即可。
那么如何对自定义的字符串属性进行序列化和反序列化呢?我们可以对属性进行更深入的了解。一个属性由两部分组成:一个 key
和一个 value
。key
是一个遵循 AttributedStringKey
协议的类型,它定义了需要什么类型的值以及用于归档的属性名称。key
还可以遵循其他协议以自定义 value
的序列化和反序列化方式。
如上代码所示:AttributedStringKey
协议只需要定义关联类型 Value
以及静态的变量 name
即可。现在假设我们希望这个 RainbowAttribute
属性 Codable
。
Codable
其实是Swift
标准库中的一个类型别名,它代表的是Decodable
和Encodable
协议。
只需要像上面代码一样,让属性遵循 CodableAttributedStringKey
协议,该协议同样的也是 DecodableAttributedStringKey
和 EncodableAttributedStringKey
的类型别名。同时,让 Value
类型遵循 Codable
协议即可。
而如果想要上面的属性是我们的本地化字符串的一部分的话,只需要再遵循一个 MarkdownDecodableAttributedStringKey
协议即可。
声明一个遵循 MarkdownDecodableAttributedStringKey
协议的 AttributedString
属性,然后让属性的 value
部分遵循 Codable
协议,我们就可以在 Markdown
文本中实现富文本字符串的效果,具体使用参考下图。
上图中前两行代码在 Markdown
中十分常见,中括号中表示的是描述文本,括号中表示的是实际的 URL
。带感叹号前缀的话就是直接渲染图片出来,不带感叹号前缀的话将会渲染一个链接出来。而第三行代码展示了自定义属性的语法。
自定义属性首先会以 ^
开头,然后是一个中括号来接收文本,最后是一个括号来表示属性。属性以 JSON5
格式表示。
JSON5[3] 与 JSON 兼容,并允许使用不带引号的
key
、注释和一些其它功能。
Foundation 中的 JSON 相关的 API 也已经添加了对 JSON5 的支持。
因为自定义属性通过 JSON
进行表示,所以任何可以被 JSONDecoder
反序列化的内容自动与新的自定义 Markdown
语法兼容。
上图代码中,第一行包含了一个自定义属性,第二行包含了两个自定义属性,第三行包含了一个具有多个子属性的属性。
Scopes
是属性 key
的集合。Scopes
在反序列化 JSON
或 Markdown
时十分有用,因为它告诉了我们想要查找的属性,以及如何反序列化这些属性。
Apple 分别为
Foundation
、UIKit
、AppKit
、SwiftUI
定义了各自的Scope
。你可以定义属于你自己应用的Scope
。
AttributeScopes
的 extension
中声明了一个结构体 CaffeAppAtrributes
,这个结构体遵循了 AttributeScope
协议。然后声明了一个自定义属性 RainbowAttribute
,同时声明了一个 SwiftUIAttributes
,这可以让我们用到了 SwiftUI
内部的所有属性。而由于 scope
是支持递归嵌套的,所以也默认包含了 Foundation
的自定义属性。scope
中定义一个属性是十分有用的,因为可以让我们在接收 scope
作为参数的函数中使用 key path
语法。markdown
中加载我们的本地化字符串了。
如上图所示,本地化字体文件中的 Markdown
在被转换为 AttributedString
后,应用会找到需要设置属性的范围并将属性应用到对应范围的字符串上。而因为属性来自于本地化字体文件,这适用于所有语言。
Formatters
有了全新的 API
,作为 Foundation
框架另一个长期存在的功能,它们负责接收像数字、日期、时间等数据然后转换成本地化的,用户可读性更高的字符串。由于 Formatters
底层由相当多的配置数据支撑,所以缓存并重用 Formatters
已经成为一种常见的模式。但如果在由许多不同的代码间共享同一个 Formatter
,并不总是合适的。今年,Apple
重新设计了 Formatter
相关 API
,以提高性能与可用性。简而言之,新的 Formatters API
专注于「格式」上。
通过上面的示例代码,我们可以看到「缓存模式」在格式化器使用时的场景。这通常由两部分组成:
Formatter
Formatter
一个日期,返回一个字符串Formatters
语法那么可以简化上面的步骤吗?答案是可以的,在最新的 Formatters API
发布后,我们无需再手动创建并配置 Formatter
,同时,我们也不需要传给 Formatter
一个日期对象了,我么只需要在日期对象身上调用 formatted
方法,并指定格式化标准是什么。仅仅一行代码就完成了上面两个步骤的工作。
在 dateLabel
的内容通过新的 Formatters API
转换后,我们不妨关注下面 magnitudeLabel
的内容。看起来一行代码就完成了从浮点数到字符串的格式化,但其实这种转换隐藏了一些复杂性,并且存在一些值得注意的陷阱,稍有不慎就会得到完全错误的结果。读者需要在转换浮点数到字符串时特别注意字符串常量的修饰符。
相反,上面的新 API
更容易理解,并且可读性,可维护性也更高。通过使用 Swift
中常规的函数来声明 我们希望 magnitude
这个浮点数如何被格式为一个字符串。同时新的 API
可以实现代码自动补全和类型安全。
Apple
将会在 Foundation
中所有的十个格式化器中统一应用新的 Formatters API
,内容包括通过清理和简化接口,并底层代码重构以避免常见的错误,同时添加了一系列的新功能。
接下来,我们将深入两种最常见的格式化场景:日期与数字。
日期格式化本质上就是将一个绝对的时间点转换为我们人类所理解的日期,这其中又涉及到了「日历」以及「时区」。甚至更重要的是,还需要考虑到不同地区的人们对于日期显示的偏好不同,这种偏好我们一般称之为「语言环境」,即 locale
。接下来一起来看一下最简单的日期格式化代码是怎样编写的吧。
Date.now
获取当前时间点 date
date
对象上调用 formatted
方法得到格式化后的内容 formatted
默认的日期格式化就是如此简单,当然,就像上面例子中看得到那样,日期格式化支持多样化的配置。
新的 Formatters API
的一个重要的目标是在于创建正确的格式化时提供尽可能多的编译时支持。使用魔法字符串进行格式化会造成陷阱,这种陷阱在正常情况下看起来是正确的,但在极端情况下会产生完全错误的值。比方获取一年中的最后一天。
formatted
函数的参数,可以获得不同格式的时间表示方式。上面代码通过链式调用的方式指明需要展示年月日的信息,最终结果将会根据用户的语言环境 locale
输出对应的内容。
year()
)、月(month()
)、日(day()
)以及星期(weekday()
)函数都是支持配置的,上面代码通过配置月份参数为 wide
,从而输出了月份以及星期的完整表示内容。Formatters API
还支持输出 ISO 8601
格式的时间戳,并且在此基础上可以实现只显示年月日,然后在年月日之间指定具体的分隔符。对于每一种类型来说,可能存在不止一种的样式。比如日期,就有 dateTime
和 ISO 8601
两种显示样式。样式可用于默认配置或自定义。
API
需要指定字段(Fields
)列表,其中一些字段具有附加的选项。Apple
为格式化 API
提供了最实用的不带默认参数或仅仅一个样式名称的默认实现。UI
中的占位文本。本次更新对于格式化相互关联的两个日期也提供了新的 API
。
timeDuration
),可以格式化为组件(components
),或者是一个相对时间。Formatters
另外一个新的特性是针对 AttributedString
进行格式化。通过全新的结构体 AttributedString
以及 Formatters API
,在任何地方都可以实现格式化 AttributedString
的输出。在 watchOS
中,许多 complications
都是格式化的字符串,因为 Apple Watch
是十分个性化的设备,所以考虑到用户的偏好设置是十分重要的。下面通过 SwiftUI
中的 demo
,我们可以一探究竟。
上图是 Caffe Companion
应用的起始点,它会展示你的下一杯免费咖啡。这里有一个仅用来显示格式化日期字符串 SwiftUI
视图。通过设置日期格式化器中的语言环境(locale
)参数,可以在 SwiftUI preview
中调整不同的语言环境以预览不同的效果。
str
转换为 AttributedString
。AttributeContainer
指定要替换样式的范围为星期,并指定颜色为橘色,最后调用 replaceAttributes
方法实现如右图 Apple Watch
中的效果。
通过在 SwiftUI Preview
中添加不同的语言环境,我们可以测试出在不同语言环境下,虽然星期的显示位置不同,但是最终都正确的加上了橙色。
上面的内容都是从日期转换为字符串,接下来我们来讨论从字符串转换为日期的场景。
Date
对象的初始化构造器增加了一个新的参数 strategy
,即初始化日期对象的策略。这里我们传入的策略是一个 format
对象,该对象包含了年月日。同时,formatted
字符串是由 date
对象格式化得到的。这适用于一个输入框既可以允许用户输入一个新的日期,也可以显示输出结果。Date
对象初始化失败,所以要加上 try?
。YYYY-MM-DD
这类「魔法」字符串会来得更加简单与直观。所以从现在开始,格式化字符串为日期时,不再需要考虑应该用多少个大写的 Y
了。所谓数字格式化就是将一个整数或者浮点数转换为一个人可以阅读的内容。
memberStyle
参数声明了数组中每个元素格式化的样式。输出的结果对于不同的用户语言环境来说都是正确的。
SwiftUI
支持在 TextFeild
上设置内容格式的样式,而因为格式的样式有需要被格式化内容的类型,所以我们可以使用一个可读的但是安全的语法实现对 tip
的格式化。
关于字符串与格式化器的国际化以及本地化的更多内容可以参考本次 WWDC
的其他 Session
:Localize your SwiftUI app[4] & Streamline your localized strings[5]
最后,我们将目光转移到一个全新的功能上 -- 自动修正语法(Automatic grammar agreement)。在之前,西班牙语等语言的本地化表达自然翻译的能力受到限制,有时会导致尴尬的对话出现。这些语言需要进行转换以实现在 不同的对话中达到时态与复数的一致,有时甚至需要了解用户的首选称呼。英语也具有同样的特性,名词具有单数和复数两种形式。
我们讨论了语言中的一些术语,接下来让我们以实际的例子进行更深入的讨论吧。
在 Caffe
App 中,我们可以点餐,然后设置餐食的大小以及数量。我们先点一份沙拉。
接着我们的朋友说她也需要一份,所以我们就增加数量到两份。在英语中,salad
这个单词需要改变自己的单复数形式以匹配两份沙拉,这就叫做语法协议。这也就是说这句话中的所有单词必须相互匹配。在英语中,由于复数的问题而修正单词是一种常见的语法协议。现在切换我们的 App
到西班牙语。
这里我们点了一份 ensalada pequeña
,或者说一小份沙拉。当我们为朋友再点一份的时候,订单确认按钮需要与英语进行同样的复数化,但有一点是不同的。在西班牙语中,像「小的」这样的形容词以及「沙拉」这样的名词都需要和具体的数量达成一致。
所以,订单确认按钮上显示的是 ensaladas pequeñas
而不是 ensalada pequeña
。
我们接着讲目光锁定到饮品上,如上图所示,对于订单按钮中的文字来说,不仅需要单复数匹配正确,还需要在这些单词的词法性上达成一致。Juice
与 jugo
是阳性化的。而形容词 pequeño
「小的」也必须匹配。为了正确对这些文字进行国际化和本地化,我们最终会遇到「组合爆炸」的问题。食物、大小和数量的每个组合都需要不同的本地化字符串。在代码层面,就会出现如下所示的场景。
我们需要对每个 item
进行 switch
操作,同时还需要对选择的大小进行判断,等等。还需要一个字符串文件来正确地对每个字符串中的计数进行复数化。而现在,通过利用在系统键盘上提示用户输入这一功能的相同技术,Apple
创建了一个新的 API
,就可以轻松处理上面我们所遇到的问题了。此功能被命名为自动语法协议,因为系统会自动修复本地化字符串以使它们有正确的语法。
有了新的 Automatic Grammar Agreement
加持,代码变得更简单了。你可以在一个字符串里直接指定数 量、大小和具体的餐食。自动语法协议会通过「反射」自动修复其中的语法。让我们逐步分解一下,为了执行「反射」流程,我们需要知道字符串中的哪些部分需要做自动语法修复。幸运的是,在 Swift
中有一个全新的类型 AttributedString
AttributedString,以及在 Markdown
中可以设置自定义属性的功能。当我们导出 Caffe
项目的本地化时,我们会得到一个字符串文件,这个文件中包含我们的提示文本以及代码中的本地化字符串,比如餐食的名称以及大小。
在拉丁美洲西班牙环境下,本地化器使用重新排列语法将大小和餐食的顺序进行了调换,这是因为西班牙语中像「小的」或「大的」这样的形容词位于名词的后面。有些语言不仅在本地化文本本身上,还在文本与阅读的人之间具有一致性。自动语法协议也有助于解决这一问题。
举个例子,如上图所示,iOS
系统自带的备忘录应用在第一次使用时会弹出一个欢迎菜单。在英语中,欢迎语是 Welcome to Notes
,即欢迎使用备忘录。而在西班牙语中,则是 Te damos la bienvenida a Notas
,即我们欢迎您使用备忘录。我们希望有和英语一样的西班牙语体验。然而,在西班牙语中,bienvenido
一词必须与用户首选的称号相匹配。称号可能是几个选项之一,而具体的选项就会更改文本的内容。使用正确的称号可以带来更个性化和更具包容性的体验。
在今年的更新当中,Apple
为西班牙语用户提供了设置了称号的入口。在语言与地区的设置中,将会有一个新的称号选项。
如上图所示,用户可以选择设置不同的称号并选择是否与所有 App
共享这一设置。
上图是用户设置了女性称谓后,新的备忘录欢迎界面。
而上图是设置了男性称谓后的备忘录欢迎界面。如果我们不知道用户是否有设置过称谓,我们还是会以初始的字符串作为备选。今年,Apple
对西班牙语和英语实现了自动语法协议功能。就像系统应用备忘录的欢迎界面一样,你也可以在自己的应用中采用同样的技术。
Foundation
今年有许多强大的新功能,你可以从今天开始在你的 app
中使用它们。
AttributedString
提供了一个快速的,易用的并且 Swift
优先的接口,进而实现在一个字符串的范围中添加键值对以达到富文本的效果。你可以在 SwiftUI
中使用 Text
组件,并在本地化字符串中使用 Markdown
语法。API
将重点放在格式上,简化了代码并提高了性能。[1]WWDC21 - What's new in Foundation: https://developer.apple.com/videos/play/wwdc2021/10109/
[2]WWDC21 - What's new in Foundation: https://developer.apple.com/videos/play/wwdc2021/10109/
[3]JSON5: https://json5.org
[4]Localize your SwiftUI app: https://developer.apple.com/videos/play/wwdc2021/10220/
[5]Streamline your localized strings: https://developer.apple.com/videos/play/wwdc2021/10221/
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/pNICAta3qsgFJXGwJ6QKcg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。