20210917のSwiftに関する記事は12件です。

デバイスの傾きを検知して向きによって決めた処理をさせる。(UIDevice)

今回の内容 デバイス(iPhone自体)を傾けた時に、傾けた事を検知して傾けた向きによって処理をさせる。 コードと簡単解説 まずは、UIDevice.current.beginGeneratingDeviceOrientationNotifications()でデバイスを回転させた時の検知を始める。 デバイスの向きが変わった時、変わった向きによってmapViewのframeを対応させる。(縦長にしたり横長にしたりって感じです) ~~~一部省略~~~ @IBOutlet weak var mapView: MKMapView! let device = UIDevice.current override func viewDidLoad() { super.viewDidLoad() device.beginGeneratingDeviceOrientationNotifications() NotificationCenter.default.addObserver(self, selector: #selector(devicOrientationDetection), name: UIDevice.orientationDidChangeNotification, object: nil) ~~~一部省略~~~ } @objc func devicOrientationDetection(){ switch UIDevice.current.orientation{ case .portrait: mapView.frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY + self.view.safeAreaInsets.top, width: self.view.frame.size.width, height: self.view.frame.size.height - self.view.safeAreaInsets.bottom - self.view.safeAreaInsets.top) case .portraitUpsideDown: mapView.frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY + self.view.safeAreaInsets.top, width: self.view.frame.size.width, height: self.view.frame.size.height - self.view.safeAreaInsets.bottom - self.view.safeAreaInsets.top) case .landscapeLeft: mapView.frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY + self.view.safeAreaInsets.top, width: self.view.frame.size.width, height: self.view.frame.size.height - self.view.safeAreaInsets.bottom - self.view.safeAreaInsets.top) case .landscapeRight: mapView.frame = CGRect(x: self.view.frame.minX, y: self.view.frame.minY + self.view.safeAreaInsets.top, width: self.view.frame.size.width, height: self.view.frame.size.height - self.view.safeAreaInsets.bottom - self.view.safeAreaInsets.top) default: print("取得出来ませんでした") } } 終わり 検知自体はそこまで難しくは無いですね。 あとは、何を処理させるかですね。 まだ、UIDeviceで面白そうなプロパティがあったので試してみたいです。 ご指摘、ご質問などありましたら、コメントまでお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptから学ぶSwiftで新しく対応したasync、await

Swiftでasyncとawait機能が対応した。 自分自身Swift以外の言語の素養がなく、asyncとawaitとはなんぞやというところから勉強したのでその記録 async、awaitの学習教材としてJavaScriptの言語仕様を見ている 前提知識として、JavaScriptでのasync await Promise型  非同期処理の戻り値であり、非同期が完了するまで、その実態はundefinedになる。 戻り値が返ってきたら、その戻り値がラップされた型となる。戻り値が返ってきたタイミングで自身のthen()メソッドを呼ぶ getDate() .then(function(data) { return getYear(data) }) .then(function(year) { return getSomething(year) }) .then(function(item) { getAnotherThing(item) }) async 非同期の戻り値(Promise)が返ってくる (asyncで呼ばれるメソッドは基本バックグラウンドで実行される) async function(){ getDate() .then(function(data) { return getYear(data) }) .then(function(year) { return getSomething(year) }) .then(function(item) { getAnotherThing(item) }) }.then(function(data){ // 戻り値がPromiseなので更なるthenを実行することもできる }) await asyncな処理( Promiseが返ってくるような処理)において、Promiseの値が決定するまでその場で待機してくれる function myPromise(num) { return new Promise(function(resolve) { setTimeout(function() { resolve(num * num) }, 3000) }) } async function myAsync() { // ここで約3秒待機する const result = await myPromise(10); // ここは実行されない console.log(result); } myAsync(); awaitの使い所  then()で繋げなくて良くなる myPromise(10).then(function(data) { console.log(data); return myPromise(100) }).then(function(data) { console.log(data); return myPromise(1000) }).then(function(data) { console.log(data); }) // これをawaitを使うと下のようにかける! async function myAsyncAll() { console.log(await myPromise(10)); console.log(await myPromise(100)); console.log(await myPromise(1000)); } myAsyncAll(); Swiftで だいたい一緒 asyncのなかでUIを触りたいときはMainActor.runでメインスレッドでの実行を明示的にする enum CustomError:Error { case badURL case badImage } func fetchData(urlString:String) async -> Result<CustomModel,CustomError>{ let request = URLRequest(url: URL(string: urlString)!) guard let (data, response) = try? await URLSession.shared.data(for: request, delegate: nil),(response as? HTTPURLResponse)?.statusCode == 200 else { return .failure(.badURL) } let model = convertDataToModel(data: data) return .success(model) } struct CustomModel{ } func convertDataToModel(data:Data)->CustomModel{ return .init() } // 一回のみの実行 (fetchDataの処理が完了したら、switch文の中身を実行) func executeFetchData() async{ switch await fetchData(urlString: "http://example.com"){ case .success(let model): print(model) await MainActor.run{ [weak self] in self?.label = model.text } case .failure(let error): print(error) } } // 複数回の実行 func executeMultipleFetchData() async { switch await fetchData(urlString: "http://example.com"){ case .success(let model): print(model) await MainActor.run{ [weak self] in tableViewSectionTitle[0] = model.text } switch await fetchData(urlString: "http://example2.com"){ case .success(let model2): await MainActor.run{ [weak self] in tableViewSectionTitle[1] = model2.text } case .failure(let error): print(error) } case .failure(let error): print(error) } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSDC 2021セッション資料まとめ

iOSDC2021登壇資料、スライドのまとめです。 Twitter等で見つけ次第掲載しますが、もし資料を見かけた方or資料を公開した登壇者の方がいらっしゃいましたら、コメント等でお声がけください。 スライドや資料のリンクが見つかった場合はタイトルにリンクをつけてありますので、タイトルがリンクになっていない場合はまだ資料が見つかっていないものになります。 適宜更新を入れていく予定です。 Day 0 Track A 大規模リファクタリングの極意 forteeのリンク SwiftUIで使ったアプリを1年運用してみてわかったこと forteeのリンク Initiatives in Rakuma iOS App forteeのリンク SwiftUI で実プロダクトを音速リリースした話 forteeのリンク Track B agoraを使ってライブ配信機能を1ヶ月半でリリースした話 forteeのリンク A Swift Stack Overflow forteeのリンク 組織横断チームとサービス及び開発体制の定期健康診断 forteeのリンク iOSアプリ開発に入門して、いきなりUnity as a Libraryに挑戦してわかったこと。 forteeのリンク Track C 運用6年目・500万人が使うアプリのDBをSQLiteからFirestoreに移行した話 forteeのリンク iOSアプリ開発者がテスラを買って色々調べたりアプリを作ったりしつつまだ見ぬApple Carを想像する forteeのリンク 従業員数4000人、老舗エンタメ企業のテックカンパニーへの挑戦 forteeのリンク iOS・Androidで使えるデザインシステムをどう実装するか forteeのリンク Track D オーディオ波形を表示するために知っておくべきこと forteeのリンク PickGo for Partnerの移行方法から学ぶ 既存のネイティブアプリをFlutterへリプレイスする方法 forteeのリンク 動画プレイヤーアプリの開発を通じて学んだ機能を実現するための要点解説 forteeのリンク Track E 振り返りながら学ぶPackage Manager forteeのリンク Day 1 Track A とあるアプリのサービス終了を見届ける 〜サブスクリプション型アプリのサービス終了ベストプラクティス〜 forteeのリンク Network ExtensionでiOSデバイス上で動くパケットキャプチャを作る スクリプト入りの資料 forteeのリンク エンジニアの視点から見る(株)ゆめみの働き方 forteeのリンク 実践 iOS オープンソースプロジェクトの始め方 forteeのリンク noteのiOSアプリで実装したアクセシビリティの全て 文字起こし forteeのリンク Combine を使ったコードのテストを Scheduler で操る方法とその仕組み forteeのリンク 「スタディサプリ」がFull SwiftUIを選択した先に見えてきたもの。 forteeのリンク Track B シームレスな体験を実現する本人確認フローの構築 〜家計簿プリカB/43でのeKYC開発実例〜 forteeのリンク 日本語でもいい感じに改行したい!! forteeのリンク アプリ間連携で薬局・クリニックのユーザー体験価値を最適化した話 〜 Medpeer iOS開発〜 forteeのリンク Appleプライバシー保護の最新事情と適応戦略 forteeのリンク MDMを使って業務用アプリの初期設定を自動化する技術 forteeのリンク 宣言的UIの状態管理とアーキテクチャ - SwiftUIとGraphQLによる実践 forteeのリンク Finder Sync Extension で Mac 向け便利ツールを作ろう forteeのリンク タウンワークアプリの案件開発を支えるオフショアチームの成り立ちとこれから forteeのリンク Track C Source Editor ExtensionとSwiftSyntaxでコード自動生成ツールを作る forteeのリンク 機能ごとに動作するミニアプリでプレビューサイクルを爆速にした話 forteeのリンク だれもが当たり前に使うアプリへ noteのこれまでとこれから forteeのリンク iOSではじめるWebAR 2021 forteeのリンク 100日間AR表現を実装して見つけた面白い実装を全力解説 forteeのリンク Mediapipeを使ったARアプリ開発事例〜カメラをかざして家の中で売れるものを探そう forteeのリンク App Size Optimizationへの挑戦 forteeのリンク 歴史のある大規模アプリに Design System を導入して開発をスケールさせる forteeのリンク Track D 初めてのハードウェア対応 forteeのリンク App Store用スクリーンショットの自動生成をアラビア語対応してSwiftUIで実装してみた forteeのリンク 未知のファイル形式をCodableで読み書きするのに役立つテクニック 『Apple Watchの文字盤ファイル』 forteeのリンク バーチャル背景を導入しよう forteeのリンク Swift 5.5 async/await を支えるモナド、継続、コルーチン forteeのリンク 僕たちが『Appのプライバシーに関する質問への回答』そして『ATT』に対応するまでの物語 forteeのリンク iOSエンジニアがKMPで大規模アプリのロジック共通化をしてうまくできている話 forteeのリンク Track E React Nativeにおける状態管理サバイバルガイド Discordで貼られたpdfのリンク forteeのリンク StoreKit のこれまでとこれから forteeのリンク 知られざる課金ステータス forteeのリンク UITestを活用しまだまだ不安定なSwiftUIアプリを安定的に実務運用する方法 forteeのリンク Day 2 Track A ランタイムデバッグのススメ forteeのリンク 大規模なアプリのマルチモジュール構成の実践 forteeのリンク アプリ開発プラットフォーマー特有の開発課題とアプローチ forteeのリンク ケースに応じたUICollectionViewのレイアウト実装パターン forteeのリンク UICollectionViewの最新のAPIを使いましょう forteeのリンク iOSアプリのセキュリティ基礎 forteeのリンク Track B バックグラウンドでアプリがキルされても怖くない!アプリの状態を元に戻すリストア機能の全て forteeのリンク Hello, Swift Concurrency world. forteeのリンク KMMを使って感じたPros/Cons forteeのリンク MultipeerConnectivityを使った動画のリアルタイム端末間共有 〜料理動画撮影アプリの事例〜 forteeのリンク SwiftUI+GraphQLで新規プロダクトの継続的破壊(Continuous Destruction)に立ち向かう forteeのリンク async/awaitやactorでiOSアプリ開発がどう変わるか Before&Afterの具体例で学ぶ forteeのリンク SceneKitを使ってアプリのクオリティを劇的に上げる forteeのリンク Track C LiDARを活用したARアプリを作ろう forteeのリンク 作ってわかる!LiDARによるカメラの暗所オートフォーカス機能 forteeのリンク LINEアプリのモバイル体験改善に向けた取り組み forteeのリンク WidgetKitで良い体験を作るには forteeのリンク ローカライゼーションマネージメント プラットフォーム導入の話 forteeのリンク Swift Package中心のプロジェクト構成とその実践 forteeのリンク async/awaitの性能をDartとSwiftとの比較で読み解く forteeのリンク Track D 実践 SharePlay / Group Activities forteeのリンク あらゆる情報を楽に正しく String にフォーマットする - 令和2021年から脱却せよ forteeのリンク DateComponentsと仲良くなる forteeのリンク App Extension のスタックトレース情報からクラッシュを解析/集計する forteeのリンク オフライン編集もできる複雑なデータ構造を端末間で同期するために forteeのリンク 対話を頑張らなくても作れるSiri Shortcuts向けIntents App Extension forteeのリンク Track E 自己管理の夢と Screen Time API forteeのリンク 元ゲーム開発者が贈る描画パフォーマンス改善 forteeのリンク App Clips はどこから来たのか&何者か&どこへ行くのか forteeのリンク AVPlayerできちんとコンテンツ保護 forteeのリンク hak & tomzoh 特別企画 forteeのリンク その他(アンカンファレンス資料、LT資料など)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift で Flood Fill(塗りつぶし)

備忘用メモ NOTE 実装:dfs 問題 https://leetcode.com/problems/flood-fill/ グリッド内で任意のセルを開始地点にして4方向に隣接したセルを塗りつぶす コード // sr: row of graph // sc: cell of graph func floodFill(_ image: [[Int]], _ sr: Int, _ sc: Int, _ newColor: Int) -> [[Int]] { // ready let directions = [ [ 0, -1], // top [ 1, 0], // right [ 0, 1], // bottom [-1, 0], // left ] let lenX = image.count let lenY = image[0].count var visited = [[Bool]](repeating: [Bool](repeating: false, count: lenY), count: lenX) let prevColor = image[sr][sc] // define dfs func dfs(_ graph: inout [[Int]], _ sr: Int, _ sc: Int) { if sr < 0 || sr > lenX-1 || sc < 0 || sc > lenY-1 { return } // invalid param if graph[sr][sc] != prevColor { return } if visited[sr][sc] { return } visited[sr][sc] = true graph[sr][sc] = newColor for dir in directions { let x = dir[0], y = dir[1] dfs(&graph, sr + x, sc + y) } } // run var _image = image dfs(&_image, sr, sc) return _image } ポイント 隣接セルへの移動は directions 変数で管理 移動先を変数として定義しておく。この問題では隣接セルが4セルのことを指していたが、たまに8セルのケースもあるのでその場合は directions 変数を変更すればよいだけになる 無限ループ回避のために visited 変数で訪問済みかチェック(この問題の場合はなくても問題ないが基本的には必要)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】クロージャ、トレイリングクロージャとは

クロージャ 文の中に直接埋め込むことができる命令のかたまり メソッドの処理内容を引数にそのまま記述できる Button構造体の例 Button構造体(UI部品)のドキュメントを見ると、以下のように記述されている。 init(action: () -> void, label: () -> label) () -> void この書式は「関数の型」を表している。 ->の左側が「引数」で、右側が「戻り値の型」 つまり、引数actionには、「引数なし」で「戻り値」がない、 関数を指定すればよいということが分かる。 メソッドは関数の1種なので、引数actionにはメソッドも指定することができる。 Buttonのactionにメソッドを入れてみる 今までの説明から以下にようなコードを記載することができる // actionにメソッドを指定 Button(action: count){  Text("カウント") } // メソッドの宣言 func count(){ self.number += 1 } 上記よりButtonが押下されたnumberプロパティに1加算されることになる。 Viewなどの記述は省略しているが、プレビューだと以下のようになる 引数にクロージャを指定する 上記の記述だと、毎回Buttonの引数action:に、 メソッド名を指定しなければならない。 これが一度しか使わないメソッドの場合、コードが煩雑に見える。 そこで現れたのが「クロージャ」である クロージャは、引数にそのままメソッドの処理内容を記述できる。 // 中括弧{}に処理を記述 Button(action: {self.number += 1}){  Text("カウント") } // メソッドは不要になる // func count(){ // self.number += 1 // } クロージャの書式 今までのクロージャは「引数」や「戻り値」がないため、省略した記述をしたが、 戻り値が存在する場合は、以下の記述が必要になる // 書式 {(引数名: 型) -> 戻り値の型 in 文 } // Button Button(action: {() -> void in self.number += 1}){  Text("カウント") } トレイリングクロージャ トレイリングクロージャとは、以下の条件の場合、 そのクロージャを()の中から外に出して、引数名を省略できること。 最後の引数がクロージャの場合 Button構造体のドキュメントで以下の記述があったと思う。 init(action: () -> void, label: () -> label) 引数actionは先程クロージャにできたので、 引数labelもクロージャにすることができる。 ※ labelはButton内のテキストを指定する つまり、以下の記述が可能になる。 Button(action: { self.number += 1}, label: { Text("カウント") }) しかし、 トレイリングクロージャの条件に当てはめると、 以下の記述ができる。 // トレイリングクロージャ未使用 // 引数の最後がクロージャ Button(action: { self.number += 1}, label: { Text("カウント") }) // トレイリングクロージャを使用 // 引数名labelを省略 // クロージャを()の外に出して記述 Button(action: {() -> void in self.number += 1}){ Text("カウント") } まとめ クロージャとは、引数の中にメソッドの処理を記述することができる トレイリングクロージャとは、引数の最後がクロージャで終わる時、そのクロージャを外に出すことができる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift CustomNSErrorを利用して、より詳しいエラー情報を定義する

概要 CustomNSError を使ってより詳細なエラーを定義します。 はじめに Swiftでコーディングするとき、何かの失敗を表すときに Error を使うことがよくあるかと思います。 enum MyError: Error { case one case two } エラーを見て何が起こったかを調べて問題を解決していくことがあると思いますが、 例えば次の analyzeError のような、MyErrorに限らず何のエラーが来るかわからないError を引数に取った場合、一度NSError に変換することによってdomainやcodeなど、より詳しい情報を得ることが可能です。 enum MyError: Error { case one case two } func analyzeError(error: Error) { let nsError: NSError = error as NSError print(nsError.domain) // __lldb_expr_1.MyError print(nsError.code) // 0 print(nsError.userInfo) // [:] } analyzeError(error: MyError.one) このように、単なる Error を設定すると、domainおよびcodeは自動で決定され、userInfoには空の辞書が入っています。 CustomNSError CustomNSError を使うと、domain、codeおよびuserInfoの定義が可能になります。 errorDomain はdomain、errorCode はcode、errorUserInfo はuserInfoとして表現されるようになります。 enum YourError: Error { case one } enum MyError: CustomNSError { case one([String : Any]) case two var errorCode: Int { switch self { case .one: return 1 case .two: return 2 } } var errorUserInfo: [String: Any] { switch self { case .one(let userInfo): return userInfo case .two: return [:] } } static var errorDomain: String = "CustomMyError" } func analyzeError(error: Error) { let nsError: NSError = error as NSError print(nsError.domain) // CustomMyError print(nsError.code) // 1 print(nsError.userInfo) // ["NSUnderlyingError": __lldb_expr_7.YourError.one] } analyzeError(error: MyError.one([NSUnderlyingErrorKey : YourError.one]))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】イニシャライザとは

イニシャライザとは 構造体の初期設定を実行するメソッド 自身のプロパティに初期値を設定する どのような用途で使用されるかというと、 初期値は必ず必要だが、その初期値がインスタンスによって異なるとき。 // Macという構造体で言語、パスワードのイニシャライザを設定 struct Mac{ var language:String var passcode:String init(language:String, passcode: String){ self.language = language self.passcode = passcode } } // languageに"日本語"、passcodeに"password"が // 設定された状態でインスタンスが作成される var mac = Mac(language: "日本語", passcode: "password") イニシャライザの宣言 init(ラベル1 引数名1:型, ラベル2 引数名2:型...){ 文 } メソッドと似ているが、違いは識別子(名前)がないこと。 呼び出し方 構造体を呼び出す際に、イニシャライザの引数を設定する 通常メソッドのように、直接呼び出すことはできず、 インスタンスを作成する際に、間接的に呼び出している。 // 上記例だと、ここでイニシャライザの初期値を設定して、インスタンスを作成している var mac = Mac(language: "日本語", passcode: "password") デフォルトイニシャライザ swiftが自動で生成するイニシャライザ。 以下の場合、生成される 構造体のプロパティすべてに初期値が設定されている場合 どういうことかというと、 struct Mac{ var language = "日本語" var passcode = "password" } 上記の構造体はすべてのプロパティに初期値が設定されているので、 イニシャライザは必要ないように見える。 しかしこのような場合でも、swift内部ではイニシャライザが必要となる。 ただ、わざわざ私達がイニシャライザを記述しなくてもいいのは、 swiftが自動で補完してくれるから。 それが、デフォルトイニシャライザである。 実際は以下のような処理が内部で行われている。 struct Mac{ var language = "日本語" var passcode = "password" // 以下が自動で生成 init(){ } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift で LCA: Lowest Common Ancestor(最近共通祖先)

備忘メモ NOTE 実装:dfs (post-order) 問題:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/ コード func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { // Return null if not find nodes we are looking for. func dfs(_ root: TreeNode?) -> TreeNode? { if root == nil { return nil } if root?.val == p?.val || root?.val == q?.val { return root } // current is node we are looking for. let left = dfs(root?.left) let right = dfs(root?.right) if left == nil && right == nil { return nil } // if not find node in children. if left != nil && right != nil { return root } // if current is LCA. return left == nil ? right : left // return either if one child found node. } return dfs(root) } ポイント dfs がreturnする TreeNode だが、再帰的に呼び出されてる中で途中で意味合いがことなる。それを1つのTreeNodeという表現かつロジックで書いてあるのでやや混乱した。 再帰的に呼び出されてる dfs がreturn する値の意味は下記の2つのどちらかのケースになる。 探し当てた p または q の位置 LCA の位置 1) の通りp か q のどちらか1つを見つけたなら return するのはその見つけた p か q になるが、2) のようにchildren の両方ともが p と q を見つけてきてる場合はこのノードがLCAになる。なので、そこから上へ渡すのはLCAになる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NCMBのSwift SDKにおける非同期/同期メソッドの使い分け

NCMBの操作はREST APIを介して行います。ネットワーク処理ということは、非同期処理であるということです。非同期処理はプログラミングコードが上から下に流れない、コールバック方式になったりするので、意図した動作にならないケースがあるなど、苦労することがあります。 そこでNCMBのSwift SDKでは同期処理のように扱えるメソッドも用意しています。この記事では同期、非同期処理の使い分けを紹介します。 データを一括で検索する場合 例えばデータストア(クラウドデータベース)からデータを取り出す場合です。非同期処理の場合は次のように書きます。 query.findInBackground(callback: { result in switch result { case let .success(array): // 検索成功 // メモデータを適用 self.memos = array case let .failure(error): // 検索失敗 print("取得に失敗しました: \(error)") } }) これを同期処理で書く場合です。ぱっと見では同期処理の方が分かりやすいです。 let result = query.find() if case let .success(array) = result { self.memos = array; } 実際の描画される様子です。まず非同期の場合。 次に同期の場合。 おそらく、どちらも見た目上は変わりません。 ループ処理の伴う同期、非同期処理 次にデータを取得した後、ファイルストア(クラウドファイルストレージ)から写真データをダウンロードしてグリッドに描画する処理です。この場合、検索結果が6件あれば、6回写真のダウンロードが実行されます。 非同期の場合です。これが6回繰り返されるようなものです。 // ファイルストア用のオブジェクトを用意 let file : NCMBFile = NCMBFile(fileName: fileName) // ダウンロード実行 file.fetchInBackground(callback: { result in switch result { case let .success(data): // ダウンロード成功 self.imageData = data case let .failure(error): // ダウンロード失敗 print(error) } }) 次に同期の場合です。 // ファイルストア用のオブジェクトを用意 let file : NCMBFile = NCMBFile(fileName: fileName) // ダウンロード実行 let result = file.fetch() if case let .success(data) = result { self.imageData = data } 同期で処理した場合です。表示までにかなり時間がかかり、一気に表示されます。これはUXがよくありません。 同期処理の仕組み 同期処理は DispatchSemaphore を使って処理をwaitし、レスポンスが返ってきたら処理を再開しています。基本的に非同期処理の 〜InBackground をラッピングしているだけです。 public func find() -> NCMBResult<[T]> { var result : NCMBResult<[T]> = NCMBResult.failure(NCMBApiErrorCode.genericError) let semaphore = DispatchSemaphore(value: 0) findInBackground(callback: {(res: NCMBResult<[T]>) -> Void in result = res semaphore.signal() }) _ = semaphore.wait(timeout: DispatchTime.distantFuture) return result } このため、ループで同期処理を行うと、1つ目の写真から6つ目の写真まで順番に1つずつ取得する形になります。これだと時間がかかってしまいます。非同期処理の場合はパラレルでダウンロード処理されるので、写真の表示順番は保証されませんが、表示までは高速になります。 まとめ 同期処理を使うことでコードの見通しは良くなります。JavaScriptのasync/awaitのように使えるので、ぜひ活用してください。ただ、ループ処理中での利用は控えた方が、アプリのUXとして良いものになるはずです。 ドキュメント : 開発者向けドキュメント | ニフクラ mobile backend
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift で Topological Sort(トポロジカルソート)

備忘用のメモ Note 実装:dfs + Queue (array で擬似的に作成) 問題:https://leetcode.com/problems/course-schedule-ii/ コード // prerequisites = [[to1, from1]], [to2, from2], ... [toN, fromN]] func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { var graph = [[Int]](repeating: [], count: numCourses) var indegree = [Int](repeating: 0, count: numCourses) var visited = [Bool](repeating: false, count: numCourses) var queue = [Int]() var result = [Int]() // initialize for edge in prerequisites { let from = edge[1] let to = edge[0] graph[from].append(to) indegree[to] += 1 } for i in 0..<indegree.count where indegree[i] == 0 { queue.append(i) result.append(i) } if queue.isEmpty { return [] } // algorithm while !queue.isEmpty { let from = queue.removeFirst() visited[from] = true for to in graph[from] { indegree[to] -= 1 if indegree[to] == 0 { queue.append(to) result.append(to) } } } // guard if !indegree.allSatisfy({ $0 == 0 }) { return []} if !visited.allSatisfy({ $0 }) { return [] } return result }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIのデータ管理についてのお勉強〜値型編〜

本記事について SwiftUIのデータ管理についてのアウトプットやメモの共有です。 本文に載っているコードは、説明用であり、コピペでは動かないためご容赦ください。 前提 順番は違うが、過去にObservableObjectについて調査したため、今回は値型の場合に扱うProperty Wrappersについて調査する。 https://qiita.com/Fuyan777/items/d79eef243e2ded33780e SwiftUIのデータ管理におけるProperty Wrappers 改めて再確認... Property Wrappersの利用方針があり、大きく3つである。 データは何か? SwiftUIでは値型、参照型のデータを扱うProperty Wrapperが存在 データをどのように処理するか? 読み込みか、変更もあるのかでデータの扱いも変わる データはどこから来るか? View自身から発生、親Viewから渡される、環境値として渡されるのか @State データが値型、データの更新、データの発生源がView自身の場合は@Stateを利用 struct ParentView: View { @State private var countNum = 0 var body: some View { Button(action: { counter += 1 }, label: { Text("count: \(countNum)") }) } } @Binding データが値型、データの更新、データの発生源は親Viewなど外から渡される場合は@Bindingを利用 struct ParentView: View { @State private var countNum = 0 var body: some View { ChildView(counter: $countNum) } } struct ChildView: View { @Binding var countNum: Int var body: some View { Button(action: { counter += 1 }, label: { Text("count: \(countNum)") }) } } 終わりに 今回は以下の記事を参考に学習しました。 https://blog.personal-factory.com/2020/11/14/publish-swiftui-catalog-book/ ぜひ、参考にしてみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UIScrollView Swift

UIScrollViewの使用方法(storyboard) ①UIscrollViewをviewControllerに配置する。 ②Autolayoutを上下左右すべて0にする ③UIscrollViewの上にViewを配置する(背景色を変えるとわかりやすいかも) ④配置したViewとUIScrollviewをCmd押しながら同時選択して、右下のAdd New Aligment Constraintを選択してLeading Edges,Trailing Edges,Top Edges,BottomEdgesをすべて0に設定する ⑤viewからScrollViewの下にあるFrame Layout Guideに対してcontrolキーを押しながらドラッグアンドドロップをして、Equal Widthを選択する ⑥置いたviewのheightの制約をかける。その制約の分スクロールするようになる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む