该备忘单提供了使用 SwiftUI 的标签的一些示例等
入门 介绍 SwiftUI 提供用于声明应用程序用户界面的视图、控件和布局结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import SwiftUIstruct AlbumDetail : View { var album: Album var body: some View { List (album.songs) { song in HStack { Image (album.cover) VStack (alignment: .leading) { Text (song.title) } } } } }
SwiftUI 与 UIKit 效果一致
View(视图) Text 要在UI中显示文本,只需编写:
添加样式
1 2 3 4 5 6 Text ("Hello World" ) .font(.largeTitle) .foregroundColor(Color .green) .lineSpacing(50 ) .lineLimit(nil ) .padding()
Text 设置文本格式 1 2 3 4 5 6 7 8 9 10 static let dateFormatter: DateFormatter = { let formatter = DateFormatter () formatter.dateStyle = .long return formatter }() var now = Date ()var body: some View { Text ("Task due date: \(now, formatter: Self .dateFormatter) " ) }
Label 可以使用以下代码行在文本旁边设置图标。
1 Label ("SwiftUI CheatSheet" , systemImage: "up.icloud" )
文档 - Label
Link 可以设置URL,单击后将重定向到浏览器。
1 Link ("Click me" , destination: URL (string: "your_url" )! )
文档 - Label
Image 图片 显示与环境相关的图像的视图。
我们可以使用新的 SF Symbols
1 Image (systemName: "clock.fill" )
您可以向系统图标集添加样式以匹配您使用的字体
1 2 3 4 5 6 Image (systemName: "cloud.heavyrain.fill" ) .foregroundColor(.red) .font(.title) Image (systemName: "clock" ) .foregroundColor(.red) .font(Font .system(.largeTitle).bold())
为图像添加样式
1 2 3 Image ("foo" ) .resizable() .aspectRatio(contentMode: .fit)
文档 - Image
Shape 创建矩形的步骤
1 2 3 Rectangle () .fill(Color .red) .frame(width: 200 , height: 200 )
创建圆的步骤
1 2 3 Circle () .fill(Color .blue) .frame(width: 50 , height: 50 )
文档 - Image
ProgressView 进度视图 显示任务完成进度的视图。
1 2 3 4 5 6 @State private var progress = 0.5 VStack { ProgressView (value: progress) Button ("More" , action: { progress += 0.05 }) }
通过应用 CircularProgressViewStyle
,可以将其用作 UIActivityIndicatorView
。
1 2 ProgressView (value: progress) .progressViewStyle(CircularProgressViewStyle ())
文档 - ProgressView
Map 地图界面的视图 显示指定区域的地图
1 2 3 4 import MapKit@State var region = MKCoordinateRegion (center: .init (latitude: 37.334722 , longitude: - 122.008889 ), latitudinalMeters: 300 , longitudinalMeters: 300 )Map (coordinateRegion: $region )
您可以通过指定 interactionModes
(使用[]
禁用所有交互)来控制地图的交互。
1 2 3 4 5 6 7 8 9 10 11 12 struct PinItem : Identifiable { let id = UUID () let coordinate: CLLocationCoordinate2D } Map (coordinateRegion: $region , interactionModes: [], showsUserLocation: true , userTrackingMode: nil , annotationItems: [PinItem (coordinate: .init (latitude: 37.334722 , longitude: - 122.008889 ))]) { item in MapMarker (coordinate: item.coordinate) }
文档 - Map
Layout(布局) Background 将图像用作背景
1 2 3 4 5 6 7 Text ("Hello World" ) .font(.largeTitle) .background( Image ("hello_world" ) .resizable() .frame(width: 100 , height: 100 ) )
VStack 以垂直线排列其子项的视图
1 2 3 4 5 VStack (alignment: .center, spacing: 20 ){ Text ("Hello" ) Divider () Text ("World" ) }
创建静态可滚动列表。文档 - VStack
HStack 将其子级排列在一条水平线上的视图。
创建静态可滚动列表
1 2 3 4 5 HStack (alignment: .center, spacing: 20 ){ Text ("Hello" ) Divider () Text ("World" ) }
文档 - HStack
LazyVStack iOS 14
一种视图,将其子级排列在垂直增长的线中,仅在需要时创建项。
1 2 3 4 5 6 7 ScrollView { LazyVStack (alignment: .leading) { ForEach (1 ... 100 , id: \.self ) { Text ("Row \($0 ) " ) } } }
文档 - LazyVStack
LazyHStack 将子项排列在水平增长的线中的视图,仅在需要时创建项。
1 2 3 4 5 6 7 ScrollView (.horizontal) { LazyHStack (alignment: .center, spacing: 20 ) { ForEach (1 ... 100 , id: \.self ) { Text ("Column \($0 ) " ) } } }
文档 - LazyHStack
ZStack 覆盖其子项的视图,使子项在两个轴上对齐。
1 2 3 4 5 6 7 8 9 10 ZStack { Text ("Hello" ) .padding(10 ) .background(Color .red) .opacity(0.8 ) Text ("World" ) .padding(20 ) .background(Color .red) .offset(x: 0 , y: 40 ) }
文档 - ZStack
LazyVGrid 容器视图,将其子视图排列在垂直增长的网格中,仅在需要时创建项目。
1 2 3 4 5 6 7 8 9 var columns: [GridItem ] = Array (repeating: .init (.fixed(20 )), count: 5 )ScrollView { LazyVGrid (columns: columns) { ForEach ((0 ... 100 ), id: \.self ) { Text ("\($0 ) " ).background(Color .pink) } } }
文档 - LazyVGrid
LazyHGrid 一种容器视图,将其子视图排列在水平增长的网格中,仅在需要时创建项目。
1 2 3 4 5 6 7 8 9 10 11 12 var rows: [GridItem ] = Array ( repeating: .init (.fixed(20 )), count: 2 ) ScrollView (.horizontal) { LazyHGrid (rows: rows, alignment: .top) { ForEach ((0 ... 100 ), id: \.self ) { Text ("\($0 ) " ).background(Color .pink) } } }
文档 - LazyHGrid
Spacer 沿其包含的堆栈布局的主轴或如果不包含在堆栈中的两个轴上扩展的灵活空间。
1 2 3 4 5 HStack { Image (systemName: "clock" ) Spacer () Text ("Time" ) }
文档 - Spacer
Divider 可用于分隔其他内容的视觉元素。
1 2 3 4 5 HStack { Image (systemName: "clock" ) Divider () Text ("Time" ) }.fixedSize()
文档 - Divider
Toggle 开关选择器 在打开和关闭状态之间切换的控件。
1 2 3 4 5 @State var isShowing = true Toggle (isOn: $isShowing ) { Text ("Hello World" ) }
如果您的 Toggle
的标签只有 Text
,则可以使用此更简单的签名进行初始化。
1 Toggle ("Hello World" , isOn: $isShowing )
文档 - Toggle
在触发时执行操作的控件。
1 2 3 4 5 6 Button ( action: { print ("did tap" ) }, label: { Text ("Click Me" ) } )
如果 Button
的标签仅为 Text
,则可以使用此更简单的签名进行初始化。
1 2 3 Button ("Click Me" ) { print ("did tap" ) }
您可以通过此按钮了解一下
1 2 3 4 5 6 7 8 9 10 11 12 Button (action: { NSApplication .shared.terminate(self ) }, label: { Image (systemName: "clock" ) Text ("Click Me" ) Text ("Subtitle" ) }) .foregroundColor(Color .white) .padding() .background(Color .blue) .cornerRadius(5 )
文档 - Button
TextField 输入框 显示可编辑文本界面的控件。
1 2 3 4 5 6 @State var name: String = "John" var body: some View { TextField ("Name's placeholder" , text: $name ) .textFieldStyle(RoundedBorderTextFieldStyle ()) .padding() }
取消编辑框焦点样式。
1 2 3 4 5 6 extension NSTextField { open override var focusRingType: NSFocusRingType { get { .none } set { } } }
如何居中放置 TextField
的文本
1 2 3 4 5 6 7 8 struct ContentView : View { @State var text: String = "TextField Text" var body: some View { TextField ("Placeholder Text" , text: $text ) .padding(.all, 20 ) .multilineTextAlignment(.center) } }
文档 - TextField
SecureField 密码输入框 用户安全地输入私人文本的控件。
1 2 3 4 5 6 @State var password: String = "1234" var body: some View { SecureField ($password ) .textFieldStyle(RoundedBorderTextFieldStyle ()) .padding() }
文档 - SecureField
TextEditor 多行可滚动文本编辑器 可以显示和编辑长格式文本的视图。
1 2 3 4 5 @State private var fullText: String = "这是一些可编辑的文本..." var body: some View { TextEditor (text: $fullText ) }
设置 TextEditor
背景颜色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 extension NSTextView { open override var frame: CGRect { didSet { backgroundColor = .clear } } } struct DetailContent : View { @State private var profileText: String = "输入您的简历" var body: some View { VSplitView (){ TextEditor (text: $profileText ) .background(Color .red) } } }
文档 - TextEditor
DatePicker 日期控件 日期选择器(DatePicker)的样式也会根据其祖先而改变。 在 Form
或 List
下,它显示为单个列表行,您可以点击以展开到日期选择器(就像日历应用程序一样)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @State var selectedDate = Date ()var dateClosedRange: ClosedRange <Date > { let min = Calendar .current.date(byAdding: .day, value: - 1 , to: Date ())! let max = Calendar .current.date(byAdding: .day, value: 1 , to: Date ())! return min... max } NavigationView { Form { Section { DatePicker ( selection: $selectedDate , in: dateClosedRange, displayedComponents: .date, label: { Text ("Due Date" ) } ) } } }
在表格和列表的外部,它显示为普通的轮式拾取器
1 2 3 4 5 6 7 8 9 10 11 12 @State var selectedDate = Date ()var dateClosedRange: ClosedRange <Date > { let min = Calendar .current.date(byAdding: .day, value: - 1 , to: Date ())! let max = Calendar .current.date(byAdding: .day, value: 1 , to: Date ())! return min... max } DatePicker (selection: $selectedDate , in: dateClosedRange, displayedComponents: [.hourAndMinute, .date], label: { Text ("Due Date" ) } )
如果 DatePicker
的标签仅是纯文本,则可以使用此更简单的签名进行初始化。
1 2 DatePicker ("Due Date" , selection: $selectedDate , in: dateClosedRange, displayedComponents: [.hourAndMinute, .date])
可以使用 ClosedRange
,PartialRangeThrough
和 PartialRangeFrom
来设置 minimumDate
和 maximumDate
。
1 2 3 4 5 6 7 DatePicker ("Minimum Date" , selection: $selectedDate , in: Date ()... , displayedComponents: [.date]) DatePicker ("Maximum Date" , selection: $selectedDate , in: ... Date (), displayedComponents: [.date])
文档 - DatePicker
Slider 滑动输入条 用于从值的有界线性范围中选择一个值的控件。
1 2 3 4 5 6 @State var progress: Float = 0 Slider (value: $progress , from: 0.0 , through: 100.0 , by: 5.0 )
滑块缺少 minimumValueImage
和 maximumValueImage
,但是我们可以通过 HStack
轻松地复制它
1 2 3 4 5 6 7 8 9 @State var progress: Float = 0 HStack { Image (systemName: "sun.min" ) Slider (value: $progress , from: 0.0 , through: 100.0 , by: 5.0 ) Image (systemName: "sun.max.fill" ) }.padding()
文档 - Slider
Picker 选择控件 用于从一组互斥值中进行选择的控件。
选择器样式的更改基于其祖先,在 Form
或 List
下,它显示为单个列表行,您可以点击以进入一个显示所有可能选项的新屏幕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 NavigationView { Form { Section { Picker (selection: $selection , label: Text ("Picker Name" ), content: { Text ("Value 1" ).tag(0 ) Text ("Value 2" ).tag(1 ) Text ("Value 3" ).tag(2 ) Text ("Value 4" ).tag(3 ) }) } } }
您可以使用 .pickerStyle(WheelPickerStyle())
覆盖样式。
1 2 3 4 5 6 7 8 9 @State var mapChoioce = 0 var settings = ["Map" , "Transit" , "Satellite" ]Picker ("Options" , selection: $mapChoioce ) { ForEach (0 ..< settings.count) { index in Text (self .settings[index]) .tag(index) } }.pickerStyle(SegmentedPickerStyle ())
在 SwiftUI
中,UISegmentedControl
只是 Picker
的另一种样式。分段控制(SegmentedControl)在 iOS 13
中也焕然一新。文档 - Picker
Stepper 执行语义递增和递减操作的控件 用于执行语义递增和递减操作的控件。
1 2 3 4 5 6 @State var quantity: Int = 0 Stepper ( value: $quantity , in: 0 ... 10 , label: { Text ("Quantity \(quantity) " )} )
如果 Stepper
的标签只有 Text
,则可以使用此更简单的签名进行初始化。
1 2 3 4 5 Stepper ( "Quantity \(quantity) " , value: $quantity , in: 0 ... 10 )
如果要完全控制,他们可以提供裸机步进器,您可以在其中管理自己的数据源。
1 2 3 4 5 6 @State var quantity: Int = 0 Stepper (onIncrement: { self .quantity += 1 }, onDecrement: { self .quantity -= 1 }, label: { Text ("Quantity \(quantity) " ) })
如果您还为带有 step
的初始化程序的每个步骤指定了一个值的数量。
1 2 3 4 5 Stepper ( value: $quantity , in: 0 ... 10 , step: 2 ) { Text ("Quantity \(quantity) " ) }
文档 - Stepper
Tap 对于单次敲击
1 2 3 Text ("Tap me!" ).onTapGesture { print ("Tapped!" ) }
用于双击
1 2 3 Text ("Tap me!" ).onTapGesture(count: 2 ) { print ("Tapped!" ) }
Gesture 手势 手势如轻敲手势、长按手势、拖拉手势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Text ("Tap" ) .gesture( TapGesture () .onEnded { _ in } ) Text ("Drag Me" ) .gesture( DragGesture (minimumDistance: 50 ) .onEnded { _ in } ) Text ("Long Press" ) .gesture( LongPressGesture (minimumDuration: 2 ) .onEnded { _ in } )
OnChange onChange 是一个新的视图修改器,可用于所有 SwiftUI 视图。它允许您侦听状态更改并相应地对视图执行操作
1 2 3 4 5 6 TextEditor (text: $currentText ) .onChange(of: clearText) { value in if clearText{ currentText = "" } }
List(列表) List 列表 一个容器,用于显示排列在单列中的数据行。创建静态可滚动列表
1 2 3 4 5 List { Text ("Hello world" ) Text ("Hello world" ) Text ("Hello world" ) }
创建动态列表 1 2 3 4 let names = ["John" , "Apple" , "Seed" ]List (names) { name in Text (name) }
添加 Section
1 2 3 4 5 6 7 8 9 List { Section (header: Text ("UIKit" ), footer: Text ("We will miss you" )) { Text ("UITableView" ) } Section (header: Text ("SwiftUI" ), footer: Text ("A lot to learn" )) { Text ("List" ) } }
可混合的列表 1 2 3 4 List { Text ("Hello world" ) Image (systemName: "clock" ) }
使其分组 添加 .listStyle(GroupedListStyle())
1 2 3 4 5 6 7 8 9 10 11 List { Section (header: Text ("UIKit" ), footer: Text ("我们会想念你的" )) { Text ("UITableView" ) } Section (header: Text ("SwiftUI" ), footer: Text ("要学的东西很多" )) { Text ("List" ) } }.listStyle(GroupedListStyle ())
插入分组 要使其插入分组(.insetGrouped
),请添加 .listStyle(GroupedListStyle())
并强制使用常规水平尺寸类 .environment(\.horizontalSizeClass, .regular)
。
1 2 3 4 5 6 7 8 9 10 List { Section (header: Text ("UIKit" ), footer: Text ("We will miss you" )) { Text ("UITableView" ) } Section (header: Text ("SwiftUI" ), footer: Text ("A lot to learn" )) { Text ("List" ) } }.listStyle(GroupedListStyle ()) .environment(\.horizontalSizeClass, .regular)
插图分组已添加到 iOS 13.2
中的 SwiftUI
在 iOS 14
中,我们为此设置了专用样式。
1 .listStyle(InsetGroupedListStyle ())
文档 - List
滚动视图。
1 2 3 4 ScrollView (alwaysBounceVertical: true ) { Image ("foo" ) Text ("Hello World" ) }
文档 - ScrollView
Containers(容器) NavigationView NavigationView
或多或少类似于 UINavigationController
,它处理视图之间的导航,显示标题,将导航栏放在顶部。
1 2 3 4 NavigationView { Text ("Hello" ) .navigationBarTitle(Text ("World" ), displayMode: .inline) }
大标题使用 .large
将条形图项添加到导航视图
1 2 3 4 5 6 7 8 9 10 11 NavigationView { Text ("Hello" ) .navigationBarTitle(Text ("World" ), displayMode: .inline) .navigationBarItems( trailing: Button ( action: { print ("Going to Setting" ) }, label: { Text ("Setting" ) } ) ) }
NavigationLink 按下时触发导航演示的按钮。这是 pushViewController
的替代品
1 2 3 4 5 6 7 8 NavigationView { NavigationLink (destination: Text ("Detail" ) .navigationBarTitle(Text ("Detail" )) ) { Text ("Push" ) }.navigationBarTitle(Text ("Master" )) }
或者通过将组目标添加到自己的视图 DetailView
中,使其更具可读性
1 2 3 4 5 NavigationView { NavigationLink (destination: DetailView ()) { Text ("Push" ) }.navigationBarTitle(Text ("Master" )) }
Group Group 创建多个视图作为一个视图,同时也避免了 Stack 的10视图最大限制
1 2 3 4 5 6 7 8 9 10 11 VStack { Group { Text ("Hello" ) Text ("Hello" ) Text ("Hello" ) } Group { Text ("Hello" ) Text ("Hello" ) } }
TabView 一个视图,允许使用可交互的用户界面元素在多个子视图之间进行切换。
1 2 3 4 5 6 7 8 9 10 TabView { Text ("First View" ) .font(.title) .tabItem({ Text ("First" ) }) .tag(0 ) Text ("Second View" ) .font(.title) .tabItem({ Text ("Second" ) }) .tag(1 ) }
图像和文本在一起。 您可以在此处使用 SF Symbol
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TabView { Text ("First View" ) .font(.title) .tabItem({ Image (systemName: "circle" ) Text ("First" ) }) .tag(0 ) Text ("Second View" ) .font(.title) .tabItem(VStack { Image ("second" ) Text ("Second" ) }) .tag(1 ) }
或者您可以省略 VStack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TabView { Text ("First View" ) .font(.title) .tabItem({ Image (systemName: "circle" ) Text ("First" ) }) .tag(0 ) Text ("Second View" ) .font(.title) .tabItem({ Image ("second" ) Text ("Second" ) }) .tag(1 ) }
用于对用于数据输入的控件(例如在设置或检查器中)进行分组的容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 NavigationView { Form { Section { Text ("Plain Text" ) Stepper (value: $quantity , in: 0 ... 10 , label: { Text ("Quantity" ) }) } Section { DatePicker ($date , label: { Text ("Due Date" ) }) Picker (selection: $selection , label: Text ("Picker Name" ) , content: { Text ("Value 1" ).tag(0 ) Text ("Value 2" ).tag(1 ) Text ("Value 3" ).tag(2 ) Text ("Value 4" ).tag(3 ) }) } } }
您几乎可以在此表单中放入任何内容,它将为表单呈现适当的样式。文档 - Form
Modal Modal 过渡。我们可以显示基于布尔的 Modal。
1 2 3 4 5 6 7 8 9 10 11 @State var isModal: Bool = false var modal: some View { Text ("Modal" ) } Button ("Modal" ) { self .isModal = true }.sheet(isPresented: $isModal , content: { self .modal })
文档 - Sheet
Alert 警报演示的容器。我们可以根据布尔值显示Alert。
1 2 3 4 5 6 7 8 9 10 @State var isError: Bool = false Button ("Alert" ) { self .isError = true }.alert(isPresented: $isError , content: { Alert (title: Text ("Error" ), message: Text ("Error Reason" ), dismissButton: .default(Text ("OK" )) ) })
Alert 也与可识别项绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @State var error: AlertError ?var body: some View { Button ("Alert Error" ) { self .error = AlertError (reason: "Reason" ) }.alert(item: $error , content: { error in alert(reason: error.reason) }) } func alert (reason : String ) -> Alert { Alert (title: Text ("Error" ), message: Text (reason), dismissButton: .default(Text ("OK" )) ) } struct AlertError : Identifiable { var id: String { return reason } let reason: String }
文档 - Alert
ActionSheet 操作表演示文稿的存储类型。我们可以显示基于布尔值的 ActionSheet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @State var isSheet: Bool = false var actionSheet: ActionSheet { ActionSheet (title: Text ("Action" ), message: Text ("Description" ), buttons: [ .default(Text ("OK" ), action: { }), .destructive(Text ("Delete" ), action: { }) ] ) } Button ("Action Sheet" ) { self .isSheet = true }.actionSheet(isPresented: $isSheet , content: { self .actionSheet })
ActionSheet 也与可识别项绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @State var sheetDetail: SheetDetail ?var body: some View { Button ("Action Sheet" ) { self .sheetDetail = ModSheetDetail (body: "Detail" ) }.actionSheet(item: $sheetDetail , content: { detail in self .sheet(detail: detail.body) }) } func sheet (detail : String ) -> ActionSheet { ActionSheet (title: Text ("Action" ), message: Text (detail), buttons: [ .default(Text ("OK" ), action: { }), .destructive(Text ("Delete" ), action: { }) ] ) } struct SheetDetail : Identifiable { var id: String { return body } let body: String }
文档 - ActionSheet
SwiftData SwiftData声明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import SwiftData@Model class Person { var id: String var name: String var age: Int init (name : String , age : Int ) { self .id = UUID ().uuidString self .name = name self .age = age } }
声明@Attribute 1 2 3 4 5 6 7 8 9 10 11 12 @Model class Person { @Attribute (.unique) var id: String var name: String var age: Int init (name : String , age : Int ) { self .id = UUID ().uuidString self .name = name self .age = age } }
声明@Relationship 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Model class Person { @Attribute (.unique) var id: String var name: String var age: Int @Relationship (deleteRule: .cascade) var students: [Student ]? = [] init (name : String , age : Int ) { self .id = UUID ().uuidString self .name = name self .age = age } }
声明Transient 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Model class Person { @Attribute (.unique) var id: String var name: String @Transient var age: Int = 0 init (name : String ) { self .id = UUID ().uuidString self .name = name } }
@Query 1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct ContentView : View { @Query (sort: \.age, order: .reverse) var persons: [Person ] @Environment (\.modelContext) var modelContext var body: some View { NavigationStack () { List { ForEach (trips) { trip in } } } } }
构建ModelContainer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let container = try ModelContainer (for: Person .self )let container = try ModelContainer ( for: Person .self , configurations: ModelConfiguration (url: URL ("path" )) ) struct SwiftDataDemoApp : App { var body: some Scene { WindowGroup { ContentView () } .modelContainer(for: Person .self ) } }
构建ModelContext 1 2 3 4 5 6 7 8 9 10 struct ContextView : View { @Environment (\.modelContext) private var context } let context = container.mainContextlet context = ModelContext (container)
增、删、改 1 2 3 4 5 6 7 let person = Person (name: "Lily" , age: 10 )context.insert(person) context.delete(person) try context.save()
查询 1 2 3 4 5 6 7 let personPredicate = #Predicate <Person > { $0 .name == "Lily" && $0 .age == 10 } let descriptor = FetchDescriptor <Person >(predicate: personPredicate)let persons = try? context.fetch(descriptor)
另见