Hướng dẫn sử dụng SwiftGen cho iOS

by DaoNM2
717 views

Tìm hiểu cách mà SwiftGen giúp dễ dàng loại bỏ các chuỗi ma thuật(magic strings) trong các dự án iOS của bạn.

Là một nhà phát triển ứng dụng trên thiết bị di động, bạn có thể cảm thấy như bạn gặp phép thuật hàng ngày. Các dòng mã bạn viết sẽ được chuyển đổi thành các ứng dụng mà mọi người trên khắp thế giới có thể sử dụng. Các công cụ mà Apple cung cấp giúp biến điều kỳ diệu đó thành hiện thực và làm cho cuộc sống của bạn dễ dàng hơn. Khi tiến xa hơn vào lĩnh vực phát triển phần mềm, bạn có thể nhận ra có một thứ ma thuật mà bạn không thích: Chuỗi thần kỳ(magic strings).

Loại an toàn, khái niệm rằng các biến chỉ có thể thuộc một loại cụ thể, cung cấp cho các nhà phát triển các rào chắn(guardrails) để giữ cho các chương trình của họ an toàn. Tuy nhiên, chuỗi ma thuật đưa mã không an toàn vào các ứng dụng đó. Chuỗi ma thuật là gì? Trong quá trình phát triển iOS, bạn đã gặp phải những điều này nhiều lần. Một ví dụ trông giống như sau:

let color = UIColor(named: "green-apple")
self.title = "Welcome!"

Ví dụ này hiển thị “green-apple” và “Welcome!” được viết dưới dạng chuỗi trực tiếp trong mã của bạn. Không quá khi nói rằng tất cả các nhà phát triển đôi khi nhận thấy mình có lỗi với hành vi này.

Trên thực tế, trong quá trình phát triển iOS, bạn không có nhiều lựa chọn. Ngoài ra, Xcode không cung cấp cách nào để tránh việc này.

Những người đã làm việc trong Android có thể thấy mình run sợ trước những đoạn mã như thế này. Môi trường phát triển Android có cơ chế chuyển đổi tài nguyên ứng dụng, chẳng hạn như chuỗi, màu sắc, hình ảnh và phông chữ, thành các kiểu biến an toàn. Có rất nhiều lợi ích từ việc này, và đó là:

  • Giảm lỗi sai chính tả
  • Ngăn chặn sự trùng lặp tài nguyên không cần thiết
  • Cung cấp kiểm tra tài nguyên tại thời điểm biên dịch
  • Giúp dọn dẹp tài nguyên cũ
  • Và nhiều hơn thế nữa

Như đã nêu, các nhà phát triển iOS và macOS không có quyền truy cập vào hệ thống cung cấp sự an toàn cho loại tài nguyên này.

May mắn thay, có SwiftGen, một trình tạo mã để loại bỏ các chuỗi ma thuật trong ứng dụng của bạn. Có sẵn dưới dạng thư viện mã nguồn mở trên GitHub, bạn có thể thêm tính năng này vào các dự án iOS và macOS của mình để mang lại sự an toàn về loại và kiểm tra thời gian biên dịch của tất cả các Assets của bạn.

Trong hướng dẫn này bạn sẽ học được cách:

  • Thiết lập dự án của bạn với SwiftGen
  • Xác định các nội dung mà bạn muốn chuyển đổi
  • Xác định nơi mà code được generated
  • Tạo các templates cho phép SwiftGen generate khi dùng SwiftUI cho Fonts và màu sắc.

Getting Started

Để bắt đầu, hãy nhấp vào nút Tải xuống tài liệu dưới đây:

Có một số cách bạn có thể cài đặt SwiftGen để hoạt động với môi trường của mình như sau:

  • CocoaPods
  • Homebrew
  • Mint
  • Directly download a zipped release(Nên dùng cách này)

Link hướng dẫn cài ở đây: https://github.com/SwiftGen/SwiftGen

Trong hướng dẫn này, bạn sẽ sử dụng CocoaPods để quản lý SwiftGen.

Lưu ý: Nếu bạn không có CocoaPods, đừng lo lắng – dự án khởi động và dự án cuối cùng đã được tải xuống phần phụ thuộc. :]

Mở workspace, có tên là DrinksUp! .Xcworkspace. Vì dự án này sử dụng CocoaPods nên bạn sẽ không thể làm việc trực tiếp với DrinksUp! .Xcodeproj.

Hãy dành một chút thời gian để xem xét xung quanh trong Xcode. Dự án đã ở trạng thái hoàn thành nhưng sử dụng chuỗi để tham chiếu phông chữ, màu sắc, hình ảnh và chuỗi. Bạn sẽ chuyển đổi tất cả những thứ này vào cuối hướng dẫn.

Xây dựng và chạy và làm quen với ứng dụng.

Ứng dụng, DrinksUp !, là một cách để theo dõi các loại đồ uống thú vị mà bạn và gia đình đã thử khi đến nhà hàng hoặc ở nhà.

Thiết lập SwiftGen

Bắt đầu bằng cách mở Terminal và điều hướng đến thư mục gốc của dự án khởi động của bạn. Tiếp theo, nhập lệnh sau vào Terminal:

./Pods/SwiftGen/bin/swiftgen config init

Thao tác này sẽ tạo một tệp cấu hình, có tên là swiftgen.yml, tại thư mục gốc dự án của bạn. Nếu tệp này tự động mở trong Xcode, hãy tiếp tục và tắt nó đi.

Tiếp theo, trong workspace dự án của bạn, đi tới Files ▸ Add new file vào “DrinksUp!”…. Tìm swiftgen.yml. Đảm bảo bỏ chọn Sao chép các mục nếu cần và chọn Tạo tham chiếu thư mục.

Add SwiftGen.yml without copying file

Nhấp vào nút Thêm. Khi hoàn tất, bạn sẽ thấy swiftgen.yml ở đầu trình điều hướng Dự án, như bên dưới:

SwiftGen yml file in Project navigator

Lưu ý: Bạn có thể di chuyển tệp này đến vị trí giống như hình minh họa, nếu Xcode không thêm nó theo cách tương tự.

Tệp này là nơi bạn sẽ đặt các hướng dẫn cho SwiftGen biết tệp nào bạn muốn chuyển đổi thành mã được tạo. Loại tệp, YML , cho biết nó đang sử dụng YAML cho cú pháp của nó. Nếu bạn chưa sử dụng YAML trước đây, đây chỉ đơn giản là một cách dễ đọc hơn để xem dữ liệu được tuần tự hóa. Bạn có thể nghĩ về nó như là JSON , được đơn giản hóa.

Bây giờ, thay thế toàn bộ nội dung của swiftgen.yml bằng nội dung sau:

# 1 
input_dir:  DrinksUp! / 
# 2 
output_dir:  DrinksUp! / Generated /

Đây là những gì bạn đã thêm:

  1. Bạn đã khai báo một biến input_dir thư mục đầu vào. Điều này cho SwiftGen biết thư mục gốc để điều hướng đến tất cả các đường dẫn tệp mà bạn sẽ sớm thêm vào.
  2. Một biến khác xác định thư mục đầu ra của các tệp Swift được tạo. Bằng cách này, bạn sẽ dễ dàng theo dõi tất cả các tệp SwiftGen hơn.

Thêm Build Phase

Để chạy SwiftGen, bạn sẽ cần thêm một giai đoạn xây dựng mới vào dự án của mình. Để thực hiện việc này, hãy chọn dự án của bạn trong trình điều hướng Dự án, chọn Build Phases . Chọn + và chọn New Run Script Phase.

Add new run script to project

Đổi tên script thành SwiftGen bằng cách nhấp đúp vào tên hiện tại, Run Script . Tiếp theo, thêm phần sau vào trường văn bản của tập lệnh:

if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]]; then
  "${PODS_ROOT}/SwiftGen/bin/swiftgen"
else
  echo "warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it."
fi 

Cuối cùng, sắp xếp lại thứ tự tập lệnh để ngồi ngay sau tên tập lệnh [CP] Check Pods Manifest.lock . Các Build Phases của bạn bây giờ sẽ giống như sau:

SwiftGen script added and ordered

Build và Run. Nếu mọi thứ được thiết lập đúng cách, bạn sẽ không có bất kỳ lỗi nào. Bạn sẽ không có bất kỳ thứ gì trong thư mục Đã tạo của mình. Được rồi chúng ta đến bước tiếp theo.

Chuyển đổi XCAssets

Bây giờ, bạn đã sẵn sàng để bắt đầu xóa các chuỗi khỏi dự án của mình! Bước đầu tiên sẽ là SwiftGen tạo mã cho các tệp XCAsset trong dự án. Mở swiftgen.yml và thêm phần sau vào cuối tệp:

## XCAssets
# 1
xcassets:
  # 2
  inputs:
    - Assets.xcassets
    - Colors.xcassets
  # 3
  outputs:
    # 4
    templateName: swift5
    # 5
    output: XCAssets+Generated.swift

Đây là ý nghĩa của mỗi dòng trong số những dòng này:

  1. Mỗi loại tệp hoặc mẫu, bạn muốn chuyển đổi bằng SwiftGen yêu cầu một mục nhập ở cấp gốc là swiftgen.yml . Ở đây, điều này cho biết bạn muốn SwiftGen chuyển đổi các tệp là XCAsset .
  2. Danh sách này cho biết những tệp SwiftGen nên giới hạn chuyển đổi của nó.
  3. Bạn cần cho SwiftGen biết cách tạo đầu ra.
  4. Bạn phải cung cấp tên mẫu. Ở đây, swift5 là một mẫu mặc định được cung cấp bởi nhóm SwiftGen. Bạn sẽ học cách sử dụng các mẫu của riêng mình sau này.
  5. Cuối cùng, bạn cung cấp tên tệp mà bạn muốn mã Swift mới của mình tạo ra. Hãy nhớ rằng, bạn đã xác định output_dir ở đầu tệp, có nghĩa là nó sẽ xuất thành Generated / XCAssets + Generated.swift .

Build và Run. Nếu bạn không gặp bất kỳ lỗi nào, thì quá trình tạo mã của bạn đã hoạt động!

Thêm tệp

Mở rộng folder Generated trong trình Project navigator. Hiện tại, bạn vẫn sẽ không tìm thấy tệp mới của mình. Để thêm nó, nhấp chuột phải vào Generated và chọn Add Files to “DrinksUp!”… .

Add generated file to project

Chọn XCAssets + Generated.swift . Đảm bảo Copy items if needed không được chọn, sau đó nhấp vào Add . Bây giờ, hãy mở XCAssets + Generate.swift và quan sát. Bạn sẽ thấy enum Asset. Trong enum, bạn sẽ tìm thấy các bảng liệt kê khác được xác định phù hợp với các danh mục XCAsset mà bạn đã xác định. Ví dụ:

  • Assets: Mỗi hình ảnh trong dự án bây giờ có một thuộc tính tĩnh được xác định.
  • Colors: Tất cả các màu của ứng dụng cũng có các thuộc tính tĩnh để tham khảo.

Mở Assets.xcassets . Lưu ý rằng có một nhóm hình ảnh có tên là nội dung khởi chạy . Nhưng Assets đã khai báo tất cả các thuộc tính ảnh tĩnh ở cùng một mức. SwiftGen có thể duy trì tổ chức này cho bạn nhưng không làm như vậy theo mặc định. Mở swiftgen.yml và thay thế toàn bộ mục nhập xcassets bằng mục sau:

## XCAssets
xcassets:
  inputs:
    - Assets.xcassets
    - Colors.xcassets
  outputs:
    templateName: swift5
    # 1
    params:
       # 2
       forceProvidesNamespaces: true
       # 3
       forceFileNameEnum: true
    output: XCAssets+Generated.swift

Tại đây, bạn tận dụng khả năng của SwiftGen để tùy chỉnh đầu ra mã của bạn bằng cách thực hiện như sau:

  1. Xác định params trên outputs của bạn.
  2. forceProvidesNamespaces: Điều này sẽ duy trì không gian tên của bạn được tìm thấy trong danh mục nội dung.
  3. Tham số bổ sung này đảm bảo cho dù bạn đã cung cấp bao nhiêu tên tệp inputs, SwiftGen sẽ duy trì các bảng liệt kê riêng biệt để đại diện cho từng danh mục nội dung.

Xây dựng dự án, sau đó quay lại XCAssets + Generated.swift . Bây giờ bạn sẽ thấy Assets có một enum tên mới LaunchAssets để đại diện cho cấu trúc thư mục của bạn.

Bây giờ, đã đến lúc sử dụng mã mới được tạo này để xóa bất kỳ tham chiếu chuỗi nào đến hình ảnh. Mở DrinksListView.swift . Bạn sẽ thấy Image("milkshake")bên trong các mục trên thanh công cụ được thêm vào chế độ xem. Thay thế dòng bằng dòng sau:

Image(Asset.Assets.milkshake.name)

Ở đây, bạn đã tham chiếu tên hình ảnh cho milkshake. Hiện tại, SwiftGen không hỗ trợ làm việc trực tiếp với SwiftUI. Bạn sẽ học cách tự thêm cái này sau. Hiện tại, bạn vẫn có thể sử dụng những gì có sẵn để tải nội dung hình ảnh mà không cần tham chiếu trực tiếp đến chuỗi.

Sử dụng các mẫu cơ bản bổ sung

Có một số mẫu bổ sung mà bạn có thể tận dụng mà không cần tùy chỉnh.

Làm việc với trình tạo giao diện

Ứng dụng bạn đang làm việc đang sử dụng SwiftUI. Tuy nhiên, để giới thiệu khả năng của SwiftGen để làm việc với Trình tạo giao diện, dự án mẫu bao gồm một bảng phân cảnh và một số bộ điều khiển chế độ xem. Bắt đầu bằng cách tạo mã để hỗ trợ Trình tạo giao diện hoặc Bảng phân cảnh bằng cách thêm phần sau vào swiftgen.yml :

## Interface Builder
ib:
  inputs:
    # 1
    - .
  outputs:
    # 2
    - templateName: scenes-swift5
      output: IB-Scenes+Generated.swift
    # 3
    - templateName: segues-swift5
      output: IB-Segues+Generated.swift

Tại đây, bạn đã làm như sau:

  1. Cho SwiftGen biết rằng bạn muốn nó tìm kiếm bất kỳ tệp nào được hỗ trợ trình tạo giao diện trong thư mục gốc của dự án của bạn.
  2. Một điều tuyệt vời về SwiftGen là nó tách biệt khái niệm Cảnh khỏi Segues . Điều này cho biết tệp mà cảnh của bạn sẽ xuất ra.
  3. Cuối cùng, điều này cho biết tất cả thông tin giả mạo sẽ được xuất ra ở đâu.

Xây dựng dự án của bạn. Thêm IB-Scenes + Generate.swift và IB-Segues + Generated.swift vào nhóm Generated , giống như bạn đã làm đối với XCAssets + Generated.swift .

Giờ đây, bạn có thể thay thế thông tin cảnh hoặc thông tin xác thực trong ứng dụng.

Bắt đầu bằng cách mở InformationViewController.swift . Trong InformationViewController, thay thế việc triển khai showAbout()bằng những điều sau:

performSegue(
  withIdentifier: StoryboardSegue.Main.showAbout.rawValue, 
  sender: self)

Tất cả các segues sẽ tạo ra dưới dạng các enum trường hợp thực tế, điều này giúp mọi thứ dễ dàng hơn khi bạn kiểm tra xem segue nào được kích hoạt. Vì đơn giản, mã bạn đã thêm chỉ đang kích hoạt segue.

Tiếp theo, bên trong InformationView, thay thế makeUIViewController(context:)bằng những thứ sau:

func makeUIViewController(context: Context) -> some UIViewController {
  StoryboardScene.Main.initialScene.instantiate()
}

Ở đây, bạn đã đơn giản hóa mã cần thiết để khởi tạo bộ điều khiển chế độ xem ban đầu của bảng phân cảnh. SwiftGen cung cấp một phương thức trợ giúp để nhanh chóng truy cập cảnh ban đầu của bạn.

Xây dựng và chạy. Nhấn vào Tìm hiểu thêm ở trên cùng bên phải. Bạn sẽ thấy một phương thức xuất hiện, hiển thị cho bạn một số thông tin về ứng dụng. Điều này được gọi vào makeUIViewController(context:)để biết chế độ xem nào cần tải.

Hiển thị màn hình Tìm hiểu thêm

Bây giờ, hãy nhấn vào nút About . Bạn sẽ kích hoạt segue mà bạn đã sửa đổi.

Đồ uốngUp!  Giới thiệu về màn hình

Làm việc với JSON

Cuối cùng chúng ta sẽ thêm phần hỗ trợ cho JSON. Thêm phần sau vào cuối swiftgen.yml :

## JSON
json:
  inputs:
    - Resources/
  outputs:
    templateName: runtime-swift5
    output: JSON+Generated.swift

Điều này hiện cung cấp một cách để tham chiếu đến bất kỳ tệp JSON nào bạn có trong tài nguyên của dự án. Bạn sẽ sử dụng điều này để chuyển đổi dữ liệu giả đi kèm với ứng dụng.

Xây dựng dự án, sau đó thêm JSON + Generated.swift vào nhóm Đã tạo của bạn .

Bây giờ, hãy mở Drink.swift . Loại bỏ hoàn toàn các struct tên được đặt tên MockData. Sau đó, thay thế phần mở rộng cho DrinkStore, được tìm thấy ở dưới cùng, bằng phần mở rộng sau:

extension DrinkStore {
  static var mockData: [Drink] {
    do {
      let data = try JSONSerialization.data(
        withJSONObject: JSONFiles.starterDrinks,
        options: [])
      let mockDrinks = try JSONDecoder().decode([Drink].self, from: data)
      return mockDrinks
    } catch {
      print(error.localizedDescription)
      return []
    }
  }
}

Tại đây, bạn sẽ thấy các tham chiếu mã của mình JSONFiles.starterDrinks. Mở MockData.json và nhận thấy khóa đầu tiên trong tệp, có tên là starterDrinks . SwiftGen đã lấy đối tượng cấp cao nhất này và cung cấp nó dưới dạng thuộc tính tĩnh trên JSONFiles để bạn tham khảo khi cần.

Xây dựng và chạy. Bạn sẽ không nhận thấy bất cứ điều gì khác so với trước đây – chỉ là đồ uống hiển thị trong danh sách.

Thức uống

Làm việc với chuỗi

Có lẽ một trong những tiện ích lớn nhất mà SwiftGen cung cấp là khả năng sử dụng các biến để tham chiếu các chuỗi được bản địa hóa(Localized Strings). Đó là một thực tiễn tuyệt vời để đặt bất kỳ văn bản nào bạn sẽ trình bày cho người dùng ứng dụng của mình bên trong các tệp strings hoặc tệp stringsdict được bản địa hóa . Nhưng nếu bạn đã làm điều này, bạn biết rằng một khi bạn vượt quá một số chuỗi, sẽ trở nên khó khăn để nhớ những chuỗi nào có sẵn. Cũng có cảm giác thừa rằng bạn có một chuỗi trong tệp chuỗi và… một chuỗi trong mã của bạn.

Dự án này chứa các tệp chuỗi sau:

  • Localizable.strings : Tệp chuỗi run of the-mill của bạn, được tạo bằng các khóa và giá trị.
  • Localizable.stringsdict : Bạn nên sử dụng các tệp stringdict bất cứ khi nào bạn cần lo lắng về các chuỗi đa nguyên. Loại tệp này không chỉ hỗ trợ dịch các chuỗi mà còn hỗ trợ cách đa hóa các từ cho bất kỳ biến thể nào mà một ngôn ngữ yêu cầu.

Để chuyển đổi tất cả các tệp chuỗi của bạn, hãy thêm phần sau vào swiftgen.yml :

## Strings
strings:
  inputs:
    # 1
    - en.lproj
  outputs:
    - templateName: structured-swift5
      # 2
      params:
        publicAccess: true
      output: Strings+Generated.swift

Bạn nên biết một số điều quan trọng về những gì bạn đã thêm ở đây:

  1. Khi bạn chuyển đổi các tệp chuỗi của mình, bạn chỉ nên sử dụng một trong các thư mục được bản địa hóa. Đối với mỗi ngôn ngữ được thêm vào, một thư mục bản địa hóa mới sẽ được tạo. Trong dự án này, bản địa hóa duy nhất là tiếng Anh. Nếu bạn thêm nhiều ngôn ngữ hơn, không cần phải sửa đổi mục nhập này để nhận các bản dịch bổ sung đó. Bởi vì tệp chuỗi phải có một tập hợp các khóa và giá trị phù hợp, bạn sẽ tham chiếu các bản dịch giống như bạn sẽ làm nếu bạn không sử dụng SwiftGen.
  2. Bạn đã thêm một tham số mới, được đặt tên publicAccess. Nếu bạn nhìn xung quanh bất kỳ tệp nào đã tạo mà bạn đã thêm, bạn sẽ thấy tất cả các loại đều có công cụ sửa đổi quyền truy cập internal. Bằng cách sử dụng tham số này, bạn có thể thay đổi công cụ sửa đổi quyền truy cập của các bảng kê đã tạo thành công khai.

Build dự án, sau đó thêm Strings + Generated.swift vào nhóm Generated . Trước khi bạn chuyển đổi tất cả các chuỗi trong ứng dụng, điều quan trọng là phải hiểu tệp này hơi khác một chút như thế nào.

Hiểu tệp

Mở Strings + Generated.swift . Bạn sẽ thấy kiểu cha được tạo, được đặt tên L10n. Trong phần này enum, bạn sẽ thấy một số kiểu con được tạo bên trong nó DrinkDetailNavigationvà DrinkList. Chúng tương ứng với các chuỗi được khai báo trong Localizable.strings .

Mở Localizable.strings và xem cách nó khai báo mục nhập đầu tiên:

"DrinkList.Navigation.Title" = "Drinks";

Lưu ý cách khai báo khóa bằng ký hiệu không gian tên bằng dấu chấm:

  • DrinkList : Điều này cho biết chuỗi này thuộc về màn hình Danh sách đồ uống.
  • Navigation : Cho biết chuỗi này sẽ được sử dụng trong thanh điều hướng.
  • Title : Cuối cùng, điều này cho biết đó là tiêu đề trong thanh điều hướng.

Bây giờ, bạn có thể chọn tổ chức và đặt tên cho các chuỗi của mình theo cách khác. Không có gì sai với điều đó – kiểu đặt tên này được sử dụng để hiển thị cách SwiftGen sẽ chuyển đổi và tổ chức mã của bạn. Đối với mỗi khoảng thời gian bạn đặt trong chuỗi của mình, SwiftGen sẽ tạo thêm một kiểu con.

Quay lại Strings + Generated.swift , bạn sẽ thấy hàm tĩnh drinksCount. SwiftGen giúp bạn dễ dàng làm việc với các chuỗi đa nguyên. Thay vì phải tạo tham chiếu đến các chuỗi được bản địa hóa và sử dụng trình định dạng chuỗi, các hàm được tạo này giúp bạn dễ dàng sử dụng một hàm lấy các giá trị của chuỗi đa nguyên của bạn.

Bây giờ, chuyển đổi tất cả các chuỗi bản địa hóa được sử dụng trong ứng dụng để trỏ đến các loại được tạo. Bắt đầu bằng cách mở DrinksListView.swift . Tiếp theo, tìm dòng mã:

Text("DrinkList.Navigation.Title")

Đổi nó thành

Text(L10n.DrinkList.Navigation.title)

Chờ một chút… L10n là gì? Đây là một phím tắt cho “bản địa hóa”. Bạn cũng có thể thấy “quốc tế hóa” được viết tắt là i18n . Nếu bạn đếm các chữ cái giữa chữ cái đầu tiên và chữ “n” cuối cùng trong một trong hai từ, bạn sẽ tìm thấy 10 hoặc 18 chữ cái tương ứng. Mặc dù điều này có ý nghĩa, sẽ không tốt nếu sử dụng một tên khác cho loại chuỗi cấp cao nhất của bạn phải không?

Mở swiftgen.yml và thêm một thuộc tính vào mục nhập chuỗi của bạn, ngay sau publicAccessđó, nó trông giống như sau:

strings:
  inputs:
    - en.lproj
  outputs:
    - templateName: structured-swift5
      params:
        publicAccess: true
        enumName: Strings
      output: Strings+Generated.swift

Ở đây, bạn đã thêm tham số enumName. Điều này cho phép bạn thay đổi loại từ “L10n” thành “Strings”.

Xây dựng và chạy. Lần này, bạn sẽ có một lỗi biên dịch. Điều này là do loại L10n không còn nữa. Truy cập DrinksListView.swift và tìm:

Text(L10n.DrinkList.Navigation.title)

Thay thế nó bằng

Text(Strings.DrinkList.Navigation.title)

Bây giờ, ứng dụng của bạn đang sử dụng tên loại mới mà bạn đã cung cấp ở bước trước.

Build ứng dụng của bạn. Bạn sẽ không còn gặp bất kỳ lỗi biên dịch nào nữa.

Lưu ý : Nếu bạn vẫn gặp lỗi, bạn có thể cần phải làm sạch dự án của mình. Chọn Product ▸ Clean and build folders , sau đó tạo lại.

Tiếp theo tìm tài sản drinkCountString. Đây là mã sử dụng tệp stringdict để xử lý cách hiển thị số lượng đồ uống trong danh sách. Thay thế nó bằng những thứ sau:

private  var drinkCountString: String {
   Strings .drinksCount (drinkStore.drinks.count)
}

Nếu bạn so sánh nó với mã ở đó trước đây, bạn có thể thấy đây là cách nhanh hơn nhiều để tham chiếu các chuỗi đa nguyên.

Bạn nên chuyển đổi tất cả các chuỗi trong dự án khỏi sử dụng chuỗi. Mở Localizable.strings và xem tất cả các khóa chuỗi. Bạn nên tìm từng cách sử dụng các khóa này trong một tệp Swift và hoán đổi nó cho các biến được tạo bởi SwiftGen.

Khi bạn hoán đổi văn bản xếp hạng trong DrinkDetailView.swift , nó sẽ sử dụng một hàm để cung cấp chuỗi, giống như cách bạn xử lý số lượng đồ uống.

Tạo mẫu tùy chỉnh

Cho đến thời điểm này, tệp swiftgen.yml của bạn đã sử dụng các mẫu mặc định do SwiftGen cung cấp. Tất cả những thứ này được lưu trữ trong SwiftGen pod. Nếu các mẫu này không cung cấp đầy đủ chức năng bạn muốn, bạn có thể tạo các mẫu của riêng mình để tạo mã theo cách bạn muốn. Các mẫu được xây dựng bằng Stencil , một dự án mã nguồn mở cung cấp ngôn ngữ tạo mẫu cho Swift. Trong phần này, bạn sẽ học cách sửa đổi các mẫu hiện có và sử dụng chúng để tạo mã của bạn.

Nếu bạn nhìn trong trình điều hướng Dự án, bạn sẽ thấy có một thư mục có tên là Mẫu . Trong đó, có hai thư mục con: Fonts và xcassets . Với những điều này, bạn sẽ được SwiftGen cung cấp hỗ trợ để sử dụng màu sắc và phông chữ trực tiếp trong SwiftUI.

Hỗ trợ màu SwiftUI

Để thêm Colorhỗ trợ SwiftUI, hãy mở asset_swift5_swiftui.stencil . Lúc đầu, mọi thứ có thể hơi choáng ngợp vì tệp không có bất kỳ hỗ trợ cú pháp mã nào.

Trên dòng 13, thêm dòng mã sau:

import SwiftUI

Tiếp theo, quay lại swiftgen.yml . Trong mục nhập đầu tiên của bạn, đối với xcassets , hãy tìm dòng nơi bạn xác định tên mẫu:

templateName:  swift5

Bây giờ, hãy thay thế nó như sau:

templatePath:  Templates / xcassets / asset_swift5_swiftui.stencil

Tại đây, bạn đã thay đổi từ sử dụng templateNamesang templatePath. Điều này yêu cầu SwiftGen sử dụng mẫu tùy chỉnh của bạn thay vì mẫu tích hợp sẵn.

Xây dựng dự án, sau đó truy cập XCAssets + Generated.swift . Ở trên cùng, bây giờ bạn sẽ thấy:

import SwiftUI

Vì bạn đã thêm nhập vào tệp Stencil nên khi mã được tạo, mã sẽ chọn thay đổi này và thêm nhập mới. Khá tuyệt, phải không?

Mở asset_swift5_swiftui.stencil và thay thế:

// Add Support For SwiftUI Here

Như dưới đây:

{{accessModifier}} private(set) lazy var color: Color = {
  Color(systemColor)
}()

Trong đoạn mã này, bạn có thể xem cách sử dụng Stencil nhiều hơn một chút. Đây là những gì bạn đã thêm:

  • {{accessModifier}}: Đây là cách bạn nói với Stencil cách thay thế bằng thứ gì đó được cung cấp trong quá trình tạo mã. Nếu bạn nhìn vào dòng 11 của tệp này, bạn sẽ thấy accessModifier được định nghĩa là một biến. Theo mặc định, công cụ sửa đổi quyền truy cập là internal. Nếu bạn nhớ từ trước, bạn đã thấy cách bạn có thể thay đổi điều này thànhpublic
  • Phần còn lại của điều này thực sự chỉ là mã tiêu chuẩn. Nó tạo ra màu SwiftUI từ màu UIKit.

Lưu ý : Có một sửa đổi khác được thực hiện đối với mẫu như một phần của vật liệu khởi động. Nó thay đổi loại Colorthành SystemColor.

Build lại dự án, sau đó quay lại XCAssets + Generated.swift . Trên dòng 62, bạn sẽ thấy mã từ mẫu của mình, hiện được tạo dưới dạng mã thực.

Bây giờ, bạn cần hoán đổi bất kỳ tham chiếu được mã hóa cứng nào thành một màu để sử dụng chức năng mới của mình. Mở DrinksListView.swift và tìm vị trí đặt màu nền trước trên văn bản tiêu đề điều hướng. Thay thế nó như sau:

Text(Strings.DrinkList.Navigation.title)
  .font(Font.custom("NotoSans-Bold", size: 17, relativeTo: .body))
  .foregroundColor(Asset.Colors.textColor.color)

Tại đây, bạn đã chuyển từ sử dụng chuỗi mã hóa cứng, với sự hỗ trợ SwiftUI thực sự để tham chiếu màu trực tiếp.

Bạn cũng có thể sử dụng màu trực tiếp trong UIKit. Mở AppMain.swift . Thay đổi dòng mã sau:

appearance.backgroundColor = UIColor(named: "header")

Thành đoạn code dưới đây:

appearance.backgroundColor = Asset.Colors.header.systemColor

Đây systemColor là tham chiếu đến loại màu cụ thể của nền tảng. Sẽ như UIColor vậy nếu bạn đang sử dụng iOS và NSColor nếu bạn đang sử dụng macOS.

Hai tệp có màu được khai báo bằng cách sử dụng chuỗi:

  • AppMain.swift
  • DrinkListView.swift

Hoàn tất chuyển đổi các màu còn lại từ việc sử dụng các chuỗi trong mỗi tệp này theo ví dụ trên.

Hỗ trợ Phông chữ SwiftUI

Cũng như SwiftUI Color hiện không được hỗ trợ trong SwiftGen, Font cũng không được hỗ trợ. Bắt đầu bằng cách mở font_swift5_swiftui.stencil và thêm nhập sau vào đầu tệp:

import SwiftUI

Tiếp theo, thay thế khối mã này được tìm thấy gần cuối tệp:

// Add Support For SwiftUI here
fileprivate extension Font {
}

Bằng đoạn code dưới đây:

fileprivate extension Font {
  // 1
  static func mappedFont(_ name: String, textStyle: TextStyle) -> Font {
    let fontStyle = mapToUIFontTextStyle(textStyle)
    let fontSize = UIFont.preferredFont(forTextStyle: fontStyle).pointSize
    return Font.custom(name, size: fontSize, relativeTo: textStyle)
  }

  // 2
  static func mapToUIFontTextStyle(
    _ textStyle: SwiftUI.Font.TextStyle
  ) -> UIFont.TextStyle {
    switch textStyle {
    case .largeTitle:
      return .largeTitle
    case .title:
      return .title1
    case .title2:
      return .title2
    case .title3:
      return .title3
    case .headline:
      return .headline
    case .subheadline:
      return .subheadline
    case .callout:
      return .callout
    case .body:
      return .body
    case .caption:
      return .caption1
    case .caption2:
      return .caption2
    case .footnote:
      return .footnote
    @unknown default:
      fatalError("Missing a TextStyle mapping")
    }
  }
}

Đây là những gì bạn đã thêm:

  1. mappedFont(_:textStyle:)tạo một phông chữ tùy chỉnh từ tên và TextStyle. Kiểu được sử dụng để lấy kích thước phông chữ tiêu chuẩn, mặc định cho mỗi phông chữ.
  2. mapToUIFontTextStyle(_:)chỉ đơn giản là cung cấp ánh xạ 1: 1 của SwiftUI TextStyletới UIKitTextStyle

Tiếp theo, tìm comment này ở giữa tệp:

// Add Support For SwiftUI Here

Thay thế nó bằng đoạn code dưới đây:

{{accessModifier}} func textStyle(_ textStyle: Font.TextStyle) -> Font {
  Font.mappedFont(name, textStyle: textStyle)
}

Khối mã này tương tự như những gì bạn đã thêm để cung cấp Color hỗ trợ. Sự khác biệt duy nhất ở đây là nó dành riêng cho việc cung cấp phông chữ trực tiếp trong SwiftUI.

Bây giờ, mở swiftgen.yml và thêm mục sau:

## Fonts
fonts:
  inputs:
    - Resources/Noto_Sans
  outputs:
    templatePath: Templates/fonts/fonts_swift5_swiftui.stencil
    output: Fonts+Generated.swift

Ứng dụng này sử dụng hai phông chữ, cả hai đều nằm trong nhóm Tài nguyên :

  1. NotoSans
  2. NotoSans-Bold

Mục nhập mới này chỉ cần biết thư mục mẹ của phông chữ bạn muốn hỗ trợ ở đâu. Mọi thứ khác tương tự như tất cả các mục nhập khác mà bạn đã thêm trước đó.

Xây dựng ứng dụng của bạn và thêm Fonts+Generated.swift vào Generated . Sau khi thực hiện, hãy mở Fonts+Generated.swift . Tại đây, bạn có thể thấy cách tổ chức họ phông chữ. Bạn sẽ thấy rằng NotoSans có sẵn các biến thể sau:

  • Thường
  • In đậm
  • In đậm nghiêng
  • In nghiêng

Giống như tất cả các mã được tạo khác trong ứng dụng, nó khá dễ sử dụng. Mở AppMain.swift và thay thế dòng đầu tiên application(_:didFinishLaunchingWithOptions:)bằng dòng sau:

let buttonFont = FontFamily.NotoSans.bold.font(size: 16)

Tại đây, bạn đặt trực tiếp kích thước phông chữ thành phông chữ NotoSans Bold(in đậm) .

Tiếp theo, truy cập DrinksListView.swift , tìm tham chiếu đầu tiên đến một phông chữ, trong NavigationLink và thay thế nó bằng như sau:

Text(drinkStore.drinks[index].name)
  .font(FontFamily.NotoSans.bold.textStyle(.body))

Tại đây, bạn tận dụng mã của mẫu tùy chỉnh của mình để có thể tạo phông chữ SwiftUI tùy chỉnh, kích thước phù hợp với mặc định TextStyle: trong trường hợp này body.

Cuối cùng, hoàn tất việc chuyển đổi tất cả các cách sử dụng của phông chữ trong toàn bộ ứng dụng. Trong cả DrinksListView.swift và DrinkDetailView.swift , bạn sẽ tìm thấy một số nơi đặt phông chữ. Theo ví dụ trên, bạn có thể chuyển đổi mã từ việc sử dụng một chuỗi sang trọng số thích hợp của NotoSans . Mỗi vị trí trong số này đã cho biết TextStylechúng nên có vị trí nào.

Build và Run. Ứng dụng của bạn trông vẫn giống như cách nó hoạt động khi bạn bắt đầu. Nhưng bây giờ bạn sẽ có tất cả các tài nguyên được tham chiếu theo cách an toàn về kiểu loại!

Thức uống

Tổng kết

Bây giờ bạn có thể sử dụng SwiftGen để:

  • Loại bỏ nhu cầu sử dụng chuỗi để tham chiếu tài nguyên trong ứng dụng của bạn, cho dù bạn sử dụng SwiftUI hay UIKit.
  • Tùy chỉnh các tệp đầu ra bằng cách sử dụng các thông số cài sẵn.
  • Sử dụng các mẫu của riêng bạn để tạo mã.

Để tìm hiểu thêm về nó, hãy xem SwiftGen trên GitHub . Bạn cũng có thể tìm hiểu thêm về Stencil trên GitHub .

Chúng tôi hy vọng bạn thích hướng dẫn này. Nếu bạn có bất kỳ câu hỏi hoặc ý kiến ​​nào, hãy tham gia thảo luận của diễn đàn bên dưới!

Nội dung bài viết được dịch từ link: https://www.raywenderlich.com/23709326-swiftgen-tutorial-for-ios

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

You may also like