20210802のSwiftに関する記事は5件です。

指定した時間後に処理をする

今回の内容 指定した秒時間後に処理をさせる コード 今回は、3秒後に3秒経過とデバックエリアに表示させます。 print("通信などの処理開始") DispatchQueue.main.asyncAfter(deadline: .now() + 3) { //tableView.reloadData()など print("3秒経過") } デバックエリア 通信などの処理開始処理開始 3秒経過 終わり ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クロージャによるイベント通知パターン(備忘録)

クロージャによるイベント通知 Swiftにおけるイベント通知パターンには3種類あり、その1つがクロージャによるイベント通知である。 クロージャを用いると、呼び出し元と同じ場所にコールバック処理を記述できるため、処理の流れを追いやすくなる。 しかし、複数のコールバック関数が必要な場合やコールバックの処理が複雑な場合はネストが深くなり可読性が下がる。 final class SomeClosure { private var num: Int = 0 func plus(completion: (Int) -> (Void)) { num = 100 //処理の完了時の結果をクロージャに渡す completion(num) } } let someClosure = SomeClosure() //処理の結果がnumに入る someClosure.plus { (num) in print("Number is \(num)") } どんなときに利用するべきか? 処理の完了イベントだけを受け取れればいいようなシンプルなケースの場合はクロージャを選択するべきであるが、コールバックの種類がいくつもある場合はデリゲートの利用も検討すべき
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftのログフレームワークXCGLoggerを使ってみた(macOS)

ログの保存先 ログファイルの保存場所は~/Library/Logs以下が標準なので、下記の通り宣言します Adding custom log locations to the OS X console application url(for: in: appropriateFor: create:) SwiftでNSDocumentDirectoryを見つける方法は? private var logFile: URL { let library = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first! return library .appendingPathComponent("Logs") .appendingPathComponent("XCGLoggerDemo.log") } 非サンドボックス環境では以下の通り /Users/<UserName>/Library/Logs/XCGLoggerDemo.log サンドボックス環境では以下の通り Containers以下は何ぞやというのは次を参照 Container Directories and File System Access /Users/<UserName>/Library/Containers/jp.co.gmail.xxx.XCGLoggerDemo/Data/Library/Logs/XCGLoggerDemo.log 実装例 CocoaPodsでインストール pod 'XCGLogger' DaveWoodCom/XCGLoggerのBasic Usage (Quick Start)の通り進める AppDelegate.swiftにXCGLoggerのグローバル変数を定義する import Cocoa import XCGLogger let log = XCGLogger.default @main class AppDelegate: NSObject, NSApplicationDelegate { applicationDidFinishLaunchingで初期設定を行う func applicationDidFinishLaunching(_ aNotification: Notification) { log.setup(level: .debug, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: logFile, fileLevel: .debug) } あとは任意の場所で以下のように呼び出せば、コンソールおよびログファイルに出力されます log.info("Hello, XCGLoggerDemo!") コンソールへの出力例 2021-08-02 22:07:21.190 [Info] > XCGLogger writing log to: file:///Users/<UserName>/Library/Logs/XCGLoggerDemo.log 2021-08-02 22:07:21.190 [Info] > XCGLoggerDemo Version: 1.0 Build: 1 PID: 57277 2021-08-02 22:07:21.190 [Info] > XCGLogger Version: 7.0.1 - Level: Debug 2021-08-02 22:07:22.438 [Info] [main] [ViewController.swift:33] saveLogFile(message:) > Hello, XCGLoggerDemo! ログファイルへの出力例
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

lazy swift

map,filterのパフォーマンスを最適化するために使用される。 指定したコレクション型や要素が使われるまで評価しないようにしてくれる(遅延評価) 通常であればmap,filterは新しいシーケンスを生成するため余計にシーケンスを作成してしまう可能性がある。 パフォーマンスの低下に繋がる恐れがある。 そこでlazyの出番になる let lazySequence = array.lazy.map{$0 + 1} let mapSequence = Array(lazySequence)//この時に発火する mapの後に記述して、,クロージャーの中の処理をキャッシュしてくれる。それをすることによって、 mapの処理が遅延し、必要なときだけ発火するようになる lazyStoredProperties lazyキーワードをストアドプロパティを宣言する前に記述してあげる 同様に必要なときだけしか呼ばれない。 インスタンス化したときに評価はされず、実際にプロパティにアクセスされた時に評価される。 struct Animal { lazy var name: String = { print("初期化が実行されました!") return "Cat" }() } // インスタンス化しても評価されない var animal = Animal() print("インスタンス化") // プロパティにアクセスして(遅れて)評価される。 let name = animal.name
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UIKitでの書き方をSwiftUIに直した物をまとめてみた。

はじめに こんにちは@kaneko77です。 次からの案件がSwiftUIを採用をしているみたいで、これまでUIKitオンリーで書いていたので色々SwiftUIの書き方をまとめました。 SwiftUIという新しい土俵(?)に上がって少し不安もありますが、UIKItでのナレッジがあるのでどうにかなるはず.... 私と同じようにこれまでUIKItオンリーでやってきたエンジニアさん多いと思います。 採用率増えてますし、Storyboard消してコードだけでレイアウト組んでるプロダクトが大半ですもんね。 ということで共有初めていきます!! こんな方対象 これまでUIKITでレイアウト組んでたけどSwiftUIやることになった方 SwiftUIについてチートシート的な感じで知っておきたい方 UIKitとSwiftUIの違い一覧 まずは一覧 引用 紹介 ちょっと先に余談 私の端末Xcode13 betaなんですが、このXcodeからSwiftUIで新しくプロジェクト作成するとinfo.plistとかSceneDelegate.swiftとかないので注意 まだXcode13の参考書とか出てるわけでもなく情報も少ないのでbetaでない方のXcodeでやることおすすめします。 一応なんで無くなったのって人のために説明 or 記事記事共有しておきます。 - info.plistが無くなった理由 参照 - SceneDelegateやAppDelegateは前のバージョンではlifecycleって項目が新規フォロジェクトを立ち上げるとあったのですがその項目自体がなくなったから自動的にSwiftUI Appが適用されることになりました。参照 余談以上です。 Text編 それではHello Worldから 定義の仕方 UIKIT.swift let testText: UILabel = { let text = UILabel() text.text = "おはよう世界!" return text }() SwiftUI.swift var body: some View { Text("おはよう世界!") } 文字色の変更 UIKIT.swift let text = UILabel() text.text = "おはよう世界!" text.textColor = .red SwiftUI.swift Text("おはよう世界!") .foregroundColor(.red) 背景色の変更 UIKIT.swift let text = UILabel() text.text = "おはよう世界!" text.backgroundColor = .black SwiftUI.swift Text("おはよう世界!") .background(Color.black) 余白 UiKitでは例えばUILabelの余白を表示しようとなるとサブクラス化したりと面倒でした.. SwiftUIからはこりゃまたびっくり!! 詳しくはこちら参照 SwiftUI.swift Text("はひふへほ") .padding(55) .background(Color.red) 文字の太さの変更 UIKIT.swift let text = UILabel() text.text = "おはよう世界!" text.font = .boldSystemFont(ofSize: 20) SwiftUI.swift Text("おはよう世界!") .bold() .font(.system(size: 20)) 複数行に対応する UIKIT.swift let text = UILabel() text.text = "おはよう\n世界!" text.numberOfLines = 0 SwiftUI.swift Text("おはよう\n世界!") .lineLimit(nil) コンテンツの表示編 SwiftUIでのコントロール(並べる)は最大10個まで 横に並べる UIKIT.swift let stackView: UIStackView = { let stack = UIStackView() stack.axis = .horizontal return stack }() let testText: UILabel = { let text = UILabel() text.text = "おはよう世界!" return text }() let testText1: UILabel = { let text = UILabel() text.text = "こんにちは世界!" return text }() addSubview(stackView) stackView.addArrangedSubview(testText) stackView.addArrangedSubview(testText1) SwiftUI.swift var body: some View { HStack{ Text("おはよう世界!") Text("こんにちは世界!") } } 縦に並べる UIKIT.swift let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical return stack }() let testText: UILabel = { let text = UILabel() text.text = "おはよう世界!" return text }() let testText1: UILabel = { let text = UILabel() text.text = "こんにちは世界!" return text }() addSubview(stackView) stackView.addArrangedSubview(testText) stackView.addArrangedSubview(testText1) SwiftUI.swift var body: some View { VStack{ Text("おはよう世界!") Text("こんにちは世界!") } } 親コンポーネントのレイアウト変更 表現が難しいですね。親コンポーネント=まとめているViewということです。 UIKIT.swift let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical stack.backgroundColor = .red return stack }() let testText: UILabel = { let text = UILabel() text.text = "おはよう世界!" return text }() let testText1: UILabel = { let text = UILabel() text.text = "こんにちは世界!" return text }() addSubview(stackView) stackView.addArrangedSubview(testText) stackView.addArrangedSubview(testText1) SwiftUI.swift var body: some View { VStack{ Text("おはよう世界!") Text("こんにちは世界!") }.background(Color.red) } 繰り返し条件を使ってレイアウトを表示 UIKIT.swift let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical return stack }() let testTexts: [UILabel] = { let text = UILabel() text.text = "hoge" let text1 = UILabel() text1.text = "huga" let text2 = UILabel() text2.text = "hugahoge" return [text, text1, text2] }() addSubview(stackView) testTexts.forEach{ stackView.addArrangedSubview($0) } SwiftUI.swift let testTexts: [Text] = [ Text("hoge"), Text("huga"), Text("hugahoge") ] var body: some View { VStack{ ForEach(0 ..< testTexts.count){ self.testTexts[$0] } }.background(Color.red) } 区切り線 UIKitだとこれUIViewで高さを1とかにして表現して作ってましたがSwiftUIだと標準で用意されているみたいです。 UIKIT.swift let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical return stack }() let testText: UILabel = { let text = UILabel() text.text = "hoge" return text }() let testText1: UILabel = { let text = UILabel() text.text = "huga" return text }() let spacer: UIView = { let view = UIView() view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1) return view }() addSubview(stackView) [testText, spacer, testText1].forEach{ stackView.addArrangedSubview($0) } SwiftUI.swift var body: some View { VStack{ Text("hoge") Divider() Text("huga") } } コンテンツをView全体に表示する UIKitだとまずview作ってそれにAutoLayout適用させて私は全体表示表現してました。 しかしこれまた簡単にできるものが用意されてます。 詳しくはこちら参照 SwiftUI.swift struct ContentView: View { private var colorView: some View { Color.init(.red) } var body: some View { colorView .edgesIgnoringSafeArea(.all) } } // 上記だったこんな風でいいです。(あくまでUIKit的に上記で書きました) struct ContentView: View { var body: some View { Color.red .edgesIgnoringSafeArea(.all) } } Button編 呼び出し方 UIKIT.swift let testButton: UIButton = { let button = UIButton() button.setTitle("ボタン", for: .normal) button.addTarget( self, action: #selector(tapped(_:)), for: .touchUpInside ) return button }() @objc func tapped(_ sender : Any) { print("タップされた") } SwiftUI.swift var body: some View { VStack{ Button(action: { print("タップされた") }, label: { Text("ボタン") }) Spacer(minLength: 0) } } TextField編 $のマークがPHPにしか見えないすね... 私はPHPちょっと案件で触ってたんですけど苦い思い出が蘇りました笑 呼び出し方 UIKIT.swift let testButton: UIButton = { let button = UIButton() button.setTitle("ボタン", for: .normal) button.backgroundColor = .red button.layer.cornerRadius = 24 return button }() let textField: UITextField = { let input = UITextField() input.placeholder = "プレースホルダー" return input }() @objc func tapped(_ sender : Any) { print("入力欄の中身", textField.text) } SwiftUI.swift @State var input = "" var body: some View { VStack{ Button(action: { print("入力欄の中身", input) }, label: { Text("ボタン") }) .background(Color.red) .cornerRadius(24) TextField("プレースホルダー", text: $input) .textFieldStyle(RoundedBorderTextFieldStyle()) } } 入力欄のパスワード形式 UIKIT.swift let textField: UITextField = { let input = UITextField() input.placeholder = "パスワードを入力してください" input.isSecureTextEntry = true return input }() SwiftUI.swift @State var pass = "" var body: some View { SecureField("パスワードを入力してください", text: $pass) } Form編 私の中で知る限りだとこれはSwiftUIでの新しい要素なのかな?と思います。 下記のような枠で囲むやつの実装です。 SwiftUI.swift @State var name = "" @State var pass = "" var body: some View { Text("タイトル").font(.title) Form{ Text("入力内容\n名前:\(name)\nパスワード\(pass)") .lineLimit(nil) TextField("名前を入力してください", text: $name) SecureField("パスワードを入力してください", text: $pass) } Spacer(minLength: 0) } Section編 これは入力できるTableViewとかでみたことがあるUIですね。 SwiftUIだとこんなに簡単にできちゃいます。 headerがあってここに書くとUITableViewでいうセクションみたいにできるというわけですね SwiftUI.swift struct ContentView: View { @State var name = "" @State var pass = "" @State var address = "" @State var tel = "" var body: some View { VStack{ Text("Section編").font(.title) Form{ Section(header: Text("ログイン情報")){ TextField("名前を入力してください", text: $name) SecureField("パスワードを入力してください", text: $pass) } Section(header: Text("パーソナル情報")){ TextField("住所", text: $address) SecureField("電話番号", text: $tel) } } Spacer(minLength: 0) } } } Table編 これは一番簡単にできると感動した物でした。 ListやFormは自身の中にスクロール機能が組み込まれています。 呼び出し UIKIT.swift //割と抜粋して書いてます。 class TestViewController: UITabBarDelegate, UITableViewDataSource { let data: [String] = ["huga", "hoge", "hugahuga"] let tableView: UITableView = { let table = UITableView(frame: .zero, style: .grouped) table.register(UITableViewCell.self, forCellReuseIdentifier: "cell") return table }() tableView.delegate = self tableView.dataSource = self self.view.addSubview(tableView) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell") cell.textLabel?.text = self.data[indexPath.row] return cell } } SwiftUI.swift struct ContentView: View { let data: [String] = ["huga", "hoge", "hugahuga"] var body: some View { VStack{ Text("Table編").font(.title) Form{ Section(header: Text("Test")){ List(data, id:\.self){ Text($0) } } } Spacer(minLength: 0) } } } カスタムセル カスタムセルってSwiftUIではないんですかね? UIKitだとカスタムセルって言われてた物も割と楽にできちゃいます。 びっくりするくらいコードがスッキリですね.....(恐ろしいSwiftUI) Identifiableプロトコルについて UIKIT.swift class CustomUITableViewCell: UITableViewCell { let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical stack.layer.borderWidth = 1 stack.layer.borderColor = UIColor.red.cgColor return stack }() let name: UILabel = UILabel() let spacer: UIView = { let view = UIView() view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1) view.backgroundColor = .gray return view }() let age: UILabel = UILabel() // 色々抜粋 ... override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: .subtitle, reuseIdentifier: reuseIdentifier ) addSubview(stackView) [name, spacer, age].forEach{ stackView.addArrangedSubview($0) } // AutoLayout抜粋 ... } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setCell(name: String, age: String) { self.name.text = name self.age.text = age } } struct CustomCell { let name: String let age: String } class TestViewController: UITabBarDelegate, UITableViewDataSource { let data: [CustomCell] = [ CustomCell(name: "山田", age: "24"), CustomCell(name: "小島", age: "83"), CustomCell(name: "岡部", age: "39") ] tableView.delegate = self tableView.dataSource = self self.view.addSubview(tableView) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomUITableViewCell cell.setCell( name: data[indexPath.row].name, age: data[indexPath.row].age ) return cell } } SwiftUI.swift struct CustomCell: View, Identifiable { var id = UUID() let name: String let age: String var body: some View{ VStack{ Text(name) .bold() .font(.headline) Divider() Text(age) }.border(Color.red) } } struct ContentView: View { let data: [CustomCell] = [ CustomCell(name: "山田", age: "24"), CustomCell(name: "小島", age: "83"), CustomCell(name: "岡部", age: "39") ] var body: some View { VStack{ Text("Table編").font(.title) Form{ Section(header: Text("Test")){ List(data){ $0 } } } Spacer(minLength: 0) } } } セルのタップ処理 UIKIT.swift //割と抜粋して書いてます。 class TestViewController: UITabBarDelegate, UITableViewDataSource { let data: [String] = ["huga", "hoge", "hugahuga"] let tableView: UITableView = { let table = UITableView(frame: .zero, style: .grouped) table.register(UITableViewCell.self, forCellReuseIdentifier: "cell") return table }() tableView.delegate = self tableView.dataSource = self self.view.addSubview(tableView) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell") cell.textLabel?.text = self.data[indexPath.row] return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("\(data[indexPath.row])が選択されました。") } } SwiftUI.swift struct ContentView: View { let data: [String] = [ "huga", "hoge", "hugahuga" ] var body: some View { VStack{ Text("Tableタップ編").font(.title) Form{ Section(header: Text("Test")){ List(data, id:\.self){ element in Text(element) .onTapGesture { print(element,"が選択されました。") } } } } Spacer(minLength: 0) } } } スクロールできるView UIKitのUIScrollViewはAutoLayout組むのが割とコードで書くの面倒ですよね。 SwiftUIで楽にできます。 呼び出し UIKIT.swift let scroll = UIScrollView() let outline = UIView() let stackView: UIStackView = { let stack = UIStackView() stack.axis = .vertical return stack }() let labels: [UILabel] = { let data = ["Test1", "Test2", "Test3", "Test4", "Test5", "Test6", "Test7", "Test8", "Test9", "Test10"] return data.map { let label = UILabel() label.text = $0 return label } }() let spacer: UIView = { let view = UIView() view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1) view.backgroundColor = .gray return view }() addSubview(scroll) scroll.addSubview(outline) outline.addSubview(stackView) labels.forEach{ stackView.addArrangedSubview($0) stackView.addArrangedSubview(spacer) } SwiftUI.swift struct ContentView: View { let data = ["Test1", "Test2", "Test3", "Test4", "Test5", "Test6", "Test7", "Test8", "Test9", "Test10"] var body: some View { VStack{ Text("スクロール編").font(.title) ScrollView{ ForEach(data, id: \.self){ Text($0) .font(.title) .padding(40) Divider() } } Spacer(minLength: 0) } } } Navgation UIKitではUINavgationControllerを使ってViewControllerに当てはめてましたが 今回からViewに直接埋め込んで使うことになりました。 UIKIT.swift UINavigationController(rootViewController: TestViewController()) SwiftUI.swift var body: some View { NavigationView{ Text("ほげ") } } ナビゲーションのタイトル UIKIT.swift self.title = "ナビゲーション" SwiftUI.swift var body: some View { NavigationView{ Text("ほげ") .navigationBarTitle(Text("ナビゲーション")) } } 画面遷移 UIKIT.swift // めちゃくちゃ抜粋しました。 // ボタンを押下してpresentする想定 present(DetailViewController.init(), animated: true, completion: nil) SwiftUI.swift struct ContentView: View { var body: some View { NavigationView{ // 画面遷移 NavigationLink("画面遷移", destination: DetailView(item: "画面遷移した")) .navigationBarTitle("選択画面") } } } struct DetailView: View { let item: String var body: some View { Text(item) } } アラート編 デフォルトアラート UIKIT.swift // ボタンを押下したら発火する定 let alert = UIAlertController(title: "表示させたいタイトル", message: "表示させたいサブタイトル", preferredStyle: .alert) let confirmAction = UIAlertAction(title: "確定", style: .default, handler:{ (action: UIAlertAction!) -> Void in print("確定") }) let cancelAction = UIAlertAction(title: "キャンセル", style: .cancel, handler:{ (action: UIAlertAction!) -> Void in print("キャンセル") }) [cancelAction, confirmAction].forEach{ alert.addAction($0) } present(alert, animated: true, completion: nil) SwiftUI.swift struct ContentView: View { @State private var isShow = false var body: some View { NavigationView{ Button("アラートの表示") { self.isShow = true } .alert(isPresented: $isShow) { Alert(title: Text("表示させたいタイトル"), message: Text("表示させたいサブタイトル"), primaryButton: .default(Text("確定"),action: { print("確定") }), secondaryButton: .cancel(Text("キャンセル"),action: { print("キャンセル") }) ) } .navigationBarTitle("選択画面") } } } アクションシート UIKIT.swift let actionSheet = UIAlertController(title: "Menu", message: "", preferredStyle: .actionSheet) let action1 = UIAlertAction(title: "表示させたいタイトル1", style: .default, handler: { (action: UIAlertAction!) in print("表示させたいタイトル1の処理") }) let action2 = UIAlertAction(title: "表示させたいタイトル2", style: .default, handler: { (action: UIAlertAction!) in print("表示させたいタイトル2の処理") }) let close = UIAlertAction(title: "閉じる", style: .destructive, handler: { (action: UIAlertAction!) in //実際の処理 print("閉じる") }) [action1,action2,close].forEach{ actionSheet.addAction($0) } self.present(actionSheet,animated: true, completion: nil) SwiftUI.swift struct ContentView: View { @State private var isShow = false var body: some View { NavigationView{ Button("アラートの表示") { self.isShow = true } .actionSheet(isPresented: $isShow) { ActionSheet(title: Text("Menu"), message: Text("メッセージ"), buttons: [ .default(Text("表示させたいタイトル1")) { print("選択肢1") }, .default(Text("表示させたいタイトル2")) { print("選択肢2") }, .cancel(Text("閉じる"), action: { print("閉じる") }) ] ) } .navigationBarTitle("選択画面") } } } modalの表示 SwiftUI.swift struct ContentView: View { @State private var isShow = false var body: some View { NavigationView{ VStack{ Button("モーダルViewを表示"){ isShow = true }.sheet(isPresented: $isShow) { DetailView() } }.navigationBarTitle("Modal画面遷移元") } } } 全体のmodalの表示 専用のものが用意されているみたいです。 UIKIT.swift let vc = UITestViewController() vc.modalPresentationStyle = .fullScreen self.present(vc, animated: true, completion: nil) SwiftUI.swift struct ContentView: View { @State private var isShow = false var body: some View { NavigationView{ VStack{ Button("モーダルViewを表示"){ isShow = true }.fullScreenCover(isPresented: $isShow) { DetailView() } }.navigationBarTitle("Modal画面遷移元") } } } 終わりに まだまだSwiftUIとUIKitの違いはあると思いますが、ひとまずは一旦これで終了したいと思います。 ある程度よく使う物たちは共有できたのかなと思います。 UIKitのコードはぱぱっと作ったコードで動確していないのでもしかしたらおかしい動作するかもしれません.. UIKitのところについては雰囲気だけお楽しみください. そこはご了承よろしくお願いいたします。 UIKitだとあんなに長かったのにってのが学習してる最中終始頭の中でその言葉が流れていました。 本当に便利になったと思います。 これからのSwiftUIライフを楽しみたいと思います!!! ここまで読んでくださりありがとうございます。 皆さんのお役に少しでも立てましたら幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む