Swift Result Builders: Description and Code Examples

The translation was prepared as part of the set for the course "iOS Developer. Professional" .



We invite everyone to an open demo lesson “Machine Learning in iOS using CoreML and CreateML: images, text, sound” . In the lesson we will discuss:



1. The main architectures of neural networks and their optimized versions for mobile devices;

2. Possibilities of CoreML 3 and 4, training on an iOS device;

3. Self-training of the image classifier using CreateML and using it with Vision;

4. Using trained models to work with text and sound in iOS.






(result builders) Swift  — « ». Swift 5.4 Xcode 12.5 . function builders (« »). , , SwiftUI.





: , Swift, . UIKit, , .





?

- (DSL), . SwiftUI @ViewBuilder



, :





struct ContentView: View {
     var body: some View {
         // This is inside a result builder
         VStack {
             Text("Hello World!") // VStack and Text are 'build blocks'
         }
     }
 }
      
      



( VStack, Text



) View



. , « » View



«» View



. , .





View



SwiftUI, , body



@ViewBuilder



:





@ViewBuilder var body: Self.Body { get }
      
      



, .





, . :





var constraints: [NSLayoutConstraint] = [
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
 ]

 // Boolean check
 if alignLogoTop {
     constraints.append(swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor))
 } else {
     constraints.append(swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor))
 }

 // Unwrap an optional
 if let fixedLogoSize = fixedLogoSize {
     constraints.append(contentsOf: [
         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width),
         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)
     ])
 }

 // Add a collection of constraints
 constraints.append(contentsOf: label.constraintsForAnchoringTo(boundsOf: view)) // Returns an array

 // Activate
 NSLayoutConstraint.activate(constraints)
      
      



, . .





 — . :





 @AutolayoutBuilder var constraints: [NSLayoutConstraint] {
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor) // Single constraint
     
     if alignLogoTop {
         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
     } else {
         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor) // Single constraint
     }
     
     if let fixedLogoSize = fixedLogoSize {
         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)
         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)
     }
     
     label.constraintsForAnchoringTo(boundsOf: view) // Returns an array
 } 
      
      



, ?





, .





AutolayoutBuilder



@resultBuilder



, :





@resultBuilder
 struct AutolayoutBuilder {     
     // .. Handle different cases, like unwrapping and collections 
 } 
      
      



« » , , . .





:





 @resultBuilder
 struct AutolayoutBuilder {
     
     static func buildBlock(_ components: NSLayoutConstraint...) -> [NSLayoutConstraint] {
         return components
     } 
 }
      
      



components (  ). , . , .





:





@AutolayoutBuilder var constraints: [NSLayoutConstraint] {
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
 } 
      
      



« »

. constraintsForAnchoringTo(boundsOf:)



, . , :





At first, the custom result builder cannot handle collections of components.
.

:





Cannot pass array of type ‘[NSLayoutConstraint]’ as variadic arguments of type ‘NSLayoutConstraint’ — «[NSLayoutConstraint]» «NSLayoutConstraint»





, Swift . . , :





List of available methods in defining custom result builder.
.

, , , . , , .





, , NSLayoutConstraint



, :





 protocol LayoutGroup {
     var constraints: [NSLayoutConstraint] { get }
 }
 extension NSLayoutConstraint: LayoutGroup {
     var constraints: [NSLayoutConstraint] { [self] }
 }
 extension Array: LayoutGroup where Element == NSLayoutConstraint {
     var constraints: [NSLayoutConstraint] { self }
 } 
      
      



, . ,  — [NSLayoutConstraint



].





, LayoutGroup



:





 @resultBuilder
 struct AutolayoutBuilder {
     
     static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {
         return components.flatMap { $0.constraints }
     }
 } 
      
      



flatMap



. , flatMap



compactMap



, compactMap flatMap: ?





, , « »:





@AutolayoutBuilder var constraints: [NSLayoutConstraint] {
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
     
     label.constraintsForAnchoringTo(boundsOf: view) // Returns an array
 } 
      
      



, , — . , .





buildOptional(..)



:





 @resultBuilder
 struct AutolayoutBuilder {
     
     static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {
         return components.flatMap { $0.constraints }
     }
     
     static func buildOptional(_ component: [LayoutGroup]?) -> [NSLayoutConstraint] {
         return component?.flatMap { $0.constraints } ?? []
     }
 } 
      
      



, .





« »:





@AutolayoutBuilder var constraints: [NSLayoutConstraint] {
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
     
     label.constraintsForAnchoringTo(boundsOf: view) // Returns an array
     
     // Unwrapping an optional
     if let fixedLogoSize = fixedLogoSize {
         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)
         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)
     }
 } 
      
      



 — . . :





 @AutolayoutBuilder var constraints: [NSLayoutConstraint] {
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
     
     label.constraintsForAnchoringTo(boundsOf: view) // Returns an array
     
     // Unwrapping an optional
     if let fixedLogoSize = fixedLogoSize {
         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)
         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)
     }
     
     // Conditional check
     if alignLogoTop {
         // Handle either the first component:
         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
     } else {
         // Or the second component:
         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor)
     }
 } 
      
      



« »:





 @resultBuilder
 struct AutolayoutBuilder {     
     static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {
         return components.flatMap { $0.constraints }
     }
     
     static func buildOptional(_ component: [LayoutGroup]?) -> [NSLayoutConstraint] {
         return component?.flatMap { $0.constraints } ?? []
     }
     
     static func buildEither(first component: [LayoutGroup]) -> [NSLayoutConstraint] {
         return component.flatMap { $0.constraints }
     }
 
     static func buildEither(second component: [LayoutGroup]) -> [NSLayoutConstraint] {
         return component.flatMap { $0.constraints }
     }
 } 
      
      



buildEither



LayoutGroup



.





, . !





. , .





 — . AutolayoutBuilder



.





, NSLayoutConstraint



, :





extension NSLayoutConstraint {
     /// Activate the layouts defined in the result builder parameter `constraints`.
     static func activate(@AutolayoutBuilder constraints: () -> [NSLayoutConstraint]) {
         activate(constraints())
     } 
      
      



:





NSLayoutConstraint.activate {
     // Single constraint
     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)
     
     label.constraintsForAnchoringTo(boundsOf: view) // Returns an array
     
     // Unwrapping an optional
     if let fixedLogoSize = fixedLogoSize {
         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)
         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)
     }
     
     // Conditional check
     if alignLogoTop {
         // Handle either the first component:
         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
     } else {
         // Or the second component:
         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor)
     }
 } 
      
      



, , UIView



:





 protocol SubviewContaining { }
 extension UIView: SubviewContaining { }
 extension SubviewContaining where Self == UIView {
     
     /// Add a child subview and directly activate the given constraints.
     func addSubview<View: UIView>(_ view: View, @AutolayoutBuilder constraints: (Self, View) -> [NSLayoutConstraint]) {
         addSubview(view)
         NSLayoutConstraint.activate(constraints(self, view))
     }
 } 
      
      



:





 let containerView = UIView()
 containerView.addSubview(label) { containerView, label in
     
     if label.numberOfLines == 1 {
         // Conditional constraints
     }
     
     // Or just use an array:
     label.constraintsForAnchoringTo(boundsOf: containerView)
     
 } 
      
      



, UIView



. , label



.





?

, , : , ?





, , , . , , .





, , . « », ( ) .





, ( ).





 — Swift 5.4. - , . , , .






"iOS Developer. Professional"





«Machine Learning iOS CoreML CreateML: , , »








All Articles