command + option + /
App Storeのアプリページに遷移して、レビュー画面を表示
guard let writeReviewURL = URL(string: "https://apps.apple.com/app/idXXXXXXXXXX?action=write-review") else { fatalError("Expected a valid URL") } UIApplication.shared.open(writeReviewURL, options: [:], completionHandler: nil)
SwiftUIのライフサイクル
@main struct SomeApp: App { @Environment(\.scenePhase) private var scenePhase var body: some Scene { WindowGroup { ContentView() }.onChange(of: scenePhase) { (phase) in switch phase { case .active: // The scene is in the foreground and interactive. case .background: // The scene isn’t currently visible in the UI. case .inactive: // The scene is in the foreground but should pause its work. @unknown default: fatalError() } } } }
RxSwiftの簡単運用
最近シンプル卓球スコアボードにRxSwiftを導入しました。点数パネルをタッチするとModel更新の同時、Viewも連動で更新するようになりました。
Model:
import Foundation import RxCocoa import RxSwift class Scoreboard { var gameL = BehaviorRelay(value: 0) var gameR = BehaviorRelay(value: 0) var scoreL = BehaviorRelay(value: 0) var scoreR = BehaviorRelay(value: 0) var serveL = BehaviorRelay(value: 2) var serveR = BehaviorRelay(value: 0) var serveFirst = Side.left }
その変化を監視したいプロパティーはBehaviorRelay<元のタイプ>にカプセル化が必要。
ViewController:
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { private var sb = Scoreboard() private let disposeBag = DisposeBag() @IBOutlet weak var scoreLeft: UIButton! override func viewDidLoad() { super.viewDidLoad() sb.scoreL .asObservable() .subscribe(onNext: { [unowned self] value in scoreLeft.setTitle("\(value)", for: .normal) }) .disposed(by: disposeBag) } @IBAction func addScoreLeft(_ sender: Any) { sb.scoreL.accept(sb.scoreL.value + 1) } }
disposeBagはこのViewControllerは消えた時、全ての監視関係を解除するためのもの。
viewDidLoadに、ModelのscoreLが変化する時、ボタンscoreLeftのTitleをscoreLの値に更新するという関係を構築する。
addScoreLeftの中、ユーザは点数パネルをタッチする時、scoreLの値+1だけ書けばいい。ボタンscoreLeftはsocreLの値変化を感知して、自動的に更新する。
全体のプロジェクトはGitHubで公開しています。
iPadでActionSheetを表示する
iPadでActionSheetを正しく呼び出す元の近くで表示させるため、popoverPresentationControllerのsourceViewとsourceRectの設定が必要です。
例:
@IBAction func dataPressed(_ sender: UIButton) { let ac = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) ac.addAction(UIAlertAction(title: "Save", style: .default, handler: nil)) ac.addAction(UIAlertAction(title: "Load", style: .default, handler: nil)) ac.addAction(UIAlertAction(title: "Restart From Beginning", style: .destructive, handler: nil)) ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) ac.popoverPresentationController?.sourceView = sender ac.popoverPresentationController?.sourceRect = sender.bounds present(ac, animated: true) }
UIKitのプロジェクトにSwiftUIのViewを呼び出す
let pcHostingController = UIHostingController(rootView: PcView(pc: selectedPc)) navigationController?.pushViewController(pcHostingController, animated: true)
Format String
let priceString = "$1" let formattedString = String(format: "Purchase colorful dice by %@", priceString) print(formattedString) >> Purchase colorful dice by $1
formatの中のPlaceholderについて、%@はString型の引数、%dはInt型の引数、%fはDouble型の引数。