- 投稿日:2021-12-30T21:35:17+09:00
RxSwift(RxCocoa)のBehaviorRelayとPublishRelayについて
はじめに 私事ですが現在個人開発を進めていまして、その中でRxSwiftを積極的に採用しています。 RxSwift自体はだいぶ触っていなかったので、過去を思い出しつつ少しまとめの記事を書こうと思います。 Relayとは さて、Rxswiftではデータバインディングのために手段としてRelayというものがあります。 これはObservableの一種で、.nextだけ流すことができます。 .nextイベントを流すためにはacceptメソッドを使います。 言い換えると.errorや.completedは流れることはないということです。 (.errorや.completedを流したいのであればSubjectを使います。) 具体的には以下の二つあります。 BehaviorRelay PublishRelay VariableはRxSwift4.0.0からBehaviorRelayに代替する形で廃止されました。 Relayの使い道 UIとモデルをバインドして変化を伝えたい時 両者の違い BehaviorRelay let behaviorRelay = BehaviorRelay<String>(value: a) behaviorRelay.subscribe { event in print(event) }.disposed(by: disposeBag) behaviorRelay.accept(b) behaviorRelay.accept(c) behaviorRelay.accept(d) // 実行結果 // next(a) // next(b) // next(c) // next(d) PublishRelay let publishRelay = PublishRelay<String>() publishRelay.subscribe { event in print(event) }.disposed(by: disposeBag) publishRelay.accept(a) publishRelay.accept(b) publishRelay.accept(c) // 実行結果 // next(a) // next(b) // next(c) 両者の違いを以下にまとめました。 BehaviorRelay PublishRelay .next ✅ ❌ 初期値 ✅ ❌ value ✅ ❌ 現在値を流すか ✅ ❌ 特に大きな違いは値を保持するかしないかの違いと言えます。 BehaviorRelayの方はsubscribeやbindした時に現在値が流れるのでデータを保持したいのであればBehaviorRelay、 そうでなければPublishRelayを使用するのが適切であると思います。 終わりに 本記事は今年最後に執筆にあたるかなと思います。最後まで読んでくださいましてありがとうございました。 来年はさらなる飛躍と成長を実現する一年にしていきたいと思います。
- 投稿日:2021-12-30T19:43:28+09:00
【Swift・Koloda】Tinderスワイプ実装できないのに毎日スワイプしてる奴いる?
はじめに 皆さんは世界的ソーシャル系マッチングアプリTinderをご存知でしょうか? 今では、若者を中心に多くのユーザ数を誇るマッチングアプリとなっています。 このアプリが人気を獲得した理由の一つにスワイプでLike,Nopeを選択できる機能があることが挙げられます。 これは直感的に好き嫌いの判別がしやすいことと、このカードをめくったら次はどんな美男美女に出会える(出てくる)のだろうというワクワクがユーザーにヒットしたのだと考えます。(自論) そんなスワイプ機能は世間ではTinderスワイプと言われてるとか言われてないとか・・・ というわけで今回は大人気Tinderスワイプを簡単に実装できるライブラリがありましたので、そちらの紹介をしながらTinderへの愛を深めていただきたいと思います。 また、今回参考にさせていただいた記事も最後に載せていますのでそちらもご覧ください。 完成イメージ図 Like,Nopeをスワイプして選択できるようにします。 また、下のボタンからもタップで選択できるようにします。 神ライブラリ「Koloda」について 今回Tinderスワイプを実装するにあたって用いるライブラリがKolodaになります。 最終ログが3年前になっていますが現在の環境(Swift5)でも問題なく使えます。 また、REARMEにも詳しい説明が書かれています。 実装 ①Kolodaのインストール 以下のコードをPodfile内に記入してターミナル上でpod installでインストールをしてください。 pod "Koloda" ②スワイプカードに表示させる画像をXcodeにいれる 適当に複数枚の画像をXcodeに入れておきましょう。 ③Storyboardの作成 Storyboardでパーツを配置していきます。 行うことは以下の3点です。 ③-1.カードを表示させる土台のUIViewを置く ③-2.置いたUIViewのクラスをKolodaViewに変更 ③-3.Like,Nopeボタンの設置 実際の図を下に載せておきます。 ④コードを書く ④-1.KolodaをControllerにインポート 適用させたいViewControllerにKolodaをインポートさせます。 import Koloda ④-2.パーツの宣言と画像を配列に格納 UIViewの宣言をします。 その際に、クラスを変更したのでkolodaView型になることを忘れずに。 また、先程入れた画像を配列の中に格納しておきましょう。 @IBOutlet weak var kolodaView: KolodaView! var imageArray = ["〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg"] ④-3.DataSourceとDelegateを適用 TableViewみたいにKolodaViewではDataSourceとDelegateを適用させてあげる必要があります。 class ViewController: UIViewController ,KolodaViewDataSource, KolodaViewDelegate {... ④-4.各々のメソッドを用いて詳細設定 DataSourceとDelegateから適当なプロトコルを使ってどのようにスワイプさせるかなどの詳細を設定していきます。 また、カード数を設定するプロトコルと内容を設定するプロトコルは記述しないとエラーになるため必ず記述する必要があります。(TableViewと同じですね) 以下では主要なプロトコルをいくつかご紹介します。 ~DataSource~ 1. kolodaNumberOfCards 表示するカードの枚数を決めます。 func koloda(_ kolodaNumberOfCards koloda: KolodaView) -> Int 2. viewForCardAt 表示するカードの内容を決めます。 func koloda(_ koloda:KolodaView viewForCardAt index:Int)-> UIView 3. DragSpeed スワイプ時のドラッグのスピードを設定できます。 速度は、slow,moderate,fastがあります。 func kolodaSpeedThatCardShouldDrag(_ koloda:KolodaView)-> DragSpeed ~Delegate~ 1. allowedDirections スワイプ時の許可するドラッグ方向を指定できます 。 デフォルトはleft,rightになりますが、斜めなどの方向も設定できます。 func koloda(_ koloda:KolodaView allowedDirectionsForIndex index:Int)-> [SwipeResultDirection] 2. DidRunOutOfCards KolodaViewに表示するカードがなくなった場合に呼び出されます。 func kolodaDidRunOutOfCards(_ koloda:KolodaView) 3. didSelectCardAt KolodaViewのカードをタップしたときに呼び出されます。 func koloda(_ koloda:KolodaView didSelectCardAt index:Int) 4. didSwipeCardAt KolodaViewのカードをスワイプしたときに呼び出されます。 方向関係なく呼び出されます。 func koloda(_ koloda:KolodaView didSwipeCardAt index:Int in direction:SwipeResultDirection) 5. shouldDragCardAt KolodaViewのカードをスワイプしてる最中に呼び出されます。 func koloda(_ koloda: KolodaView, shouldDragCardAt index: Int) -> Bool 他にもプロトコルは存在しますが、詳しくはKolodaをご覧ください。 完成コード 完成イメージのコードは以下のようになります。 import UIKit import Koloda class ViewController: UIViewController ,KolodaViewDataSource, KolodaViewDelegate { @IBOutlet weak var kolodaView: KolodaView! var imageArray = ["〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg", "〇〇.jpg"] override func viewDidLoad() { super.viewDidLoad() kolodaView.dataSource = self kolodaView.delegate = self } func kolodaNumberOfCards(_ koloda: KolodaView) -> Int { imageArray.count } func kolodaSpeedThatCardShouldDrag(_ koloda: KolodaView) -> DragSpeed { return .moderate } func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView { let imageView = UIImageView(frame: koloda.bounds) imageView.contentMode = .scaleAspectFit imageView.image = UIImage(named: imageArray[index]) koloda.addSubview(imageView) return imageView } @IBAction func Nope() { kolodaView.swipe(.left) } @IBAction func Like() { kolodaView.swipe(.right) } } おわりに 今回は、Tinderスワイプについて書きました。 本記事を書くにあたって以下の記事を参考にさせていただきました。ありがとうございます。 tinderUIをライブラリKolodaを使って実装してみよう! この記事を読んでぜひ皆さんTinderライフ楽しんでくださいね! では良いお年を。
- 投稿日:2021-12-30T18:05:26+09:00
小学生でも分かるswift構文
小学生でも分かるswift構文 初めまして!2021年12月より完全未経験からのプログラミング(swift)をスタートさせました! 初めてみたものの、まず基礎となる構文の意味が全く解らない笑 英検4級の私には「false」や「string」も良く意味がわからず、本当にプログラミングが出来るのか... 正直、おしっこをちびりそうでした。 そこで、自分の為にも、または自分と同じくらいの学力しかない人にでも、分かるように記事を書いてみようと思った次第です。 それでは、早速やっていきましょう! 構文の意味 let(レット)・・・初期のプログラミング言語で採用されていた数学用語。 それがそのまま現在まで引き継がれているようです。 constant(コンスタント)・・・定数、不変のもの。 variable(バリアブル)・・・変数、可変のもの。 型の名前 int(イント)・・・integer(インテジャ)の略。整数。 string(ストリング)・・・文字列の意。 double(ダブル)・・・変数のデータ型の一種。浮動小数点型といわれる。 bool(ブール)・・・boolean(ブーリアン)の略。変数のデータ型の一種。真理値のtrue「トゥルー(真)」とfalse「フォルス(偽)」の2つの値をとるデータ型。 今回は以上となります。 次回は実際にXcodeで入力していきたいと思います!
- 投稿日:2021-12-30T16:12:42+09:00
【Mapkit】ClusterAnnotationに含まれる情報を取得する方法
はじめに MKMapKitを使うと簡単に地図やピンが描画できてとても便利ですが、 クラスター化されたピンをタップした際のデータ取得に少し苦労したので、簡単にまとめておきます。 環境 Xcode 12.4 Swift 5.3.2 実現したかった事 緯度軽度とIDの情報を持ったピンを生成 ピンのUIはシンプルに、文字の表示もしない 全てのピンは物理接触でクラスター化され、クラスターピンには数字を表示 ピンをタップしたら画面遷移させ、その際ピンに含まれるIDを渡す 実装 まずは、カスタムアノテーションを作る。 class CustomAnnotation: NSObject, MKAnnotation { // クラスターID static let clusteringIdentifier = "locationCluster" // ピンの緯度軽度 let coordinate: CLLocationCoordinate2D // ピンのID let title: String? init(_ coordinate: CLLocationCoordinate2D, id: Int) { self.coordinate = coordinate title = String(id) } } 次に地図画面の実装(関係する箇所のみ) extension MapViewController: MKMapViewDelegate { // ピンを地図に描画する(初期表示やデータ更新時) private func drawPinsOnMap() { let span = MKCoordinateSpan(latitudeDelta: spanLatitudeDelta, longitudeDelta: spanLongitudeDelta) let center = CLLocationCoordinate2DMake(centerLatitude, centerLongitude) let region = MKCoordinateRegion(center: center, span: span) mapView.region = region var annotations: [MKAnnotation] = [] mapView.removeAnnotations(mapView.annotations) let mapData = viewModel.dataArray.value //データ取得 guard mapData.count > 0 else { return } for data in mapData { let pin = CustomAnnotation(CLLocationCoordinate2DMake(data.latitude, data.longitude), id: data.id) annotations.append(pin) } mapView.addAnnotations(annotations) } // アノテーションビューの生成 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { if annotation is MKUserLocation { return nil } else if annotation is MKClusterAnnotation { let clusterAnnoationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier, for: annotation) guard let safeCluster = clusterAnnoationView as? MKMarkerAnnotationView else { return clusterAnnoationView } safeCluster.titleVisibility = .hidden safeCluster.subtitleVisibility = .hidden return safeCluster } let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation) guard let markerAnnotationView = annotationView as? MKMarkerAnnotationView, let _ = annotation as? CustomAnnotation else { return annotationView } markerAnnotationView.clusteringIdentifier = CustomAnnotation.clusteringIdentifier markerAnnotationView.titleVisibility = .hidden markerAnnotationView.subtitleVisibility = .hidden return markerAnnotationView } // 地図上のピン押下時の処理 func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { var idList: [Int] = [] // ここでクラスターピンか単体ピンか確認して処理を変える if let cluster = view.annotation as? MKClusterAnnotation { let annotations = cluster.memberAnnotations for annotation in annotations { guard let title = annotation.title as? String else { continue } guard let id = Int(title) else { continue } idList.append(id) } } else { guard let pin = view.annotation else { return } guard let title = pin.title as? String else { return } guard let id = Int(title) else { return } photoIdList.append(id) } // ★ ここでidListを持って画面遷移させる // 必要に応じてピンのセレクト状態を解除する mapView.deselectAnnotation(view.annotation, animated: true) } } 結果 if let cluster = view.annotation as? MKClusterAnnotation { let annotations = cluster.memberAnnotations } でクラスターピンの持っている情報が取得できました。 感想 結果的に大したことなかった実装でしたが、クラスターピンからなかなかピンの情報が取得できず、ドキュメントを読みながら色々工夫してやっとできました。 参考記事
- 投稿日:2021-12-30T13:59:34+09:00
Swiftでプロパティの種類を学ぶ
おはようございます。 swift初学者です。 swiftを勉強している時に、プロパティの種類が多すぎて混乱してしましました。 なので本記事では、備忘録としてプロパティの種類を整理すべく、各プロパティの特徴や性質をしていこうと思います。 そもそもプロパティとは プロパティとは、クラスや構造体などに紐付いた値の事を指します。 構造体でいうと以下の通りです。 example.swift struct Person { var name:String //プロパティ var age:Int //プロパティ } let Myname = Person(name:"naoki",age: 23) print(Myname.name) このように、クラスや構造体の構成要素になります。 プロパティの種類 プロパティには主に二つの種類に分けることができます。 値の保持により分類されるプロパティ 定義される対象により分類されるプロパティ この二つに分類されます。 値の保持による分類 値の保持による分類は二つ存在します。 ストアドプロパティ コンピューテッドプロパティ それぞれの特徴を紹介していきます。 ストアドプロパティ ストアドプロパティは値を保持するプロパティになります。 example.swift struct Person { var name:String = "naoki"//プロパティ var age:Int = 10 //プロパティ } let Myname = Person() print(Myname.name)//"naoki" print(Myname.age)//10 ストアドプロパティには、値の変更を監視するプロパティオブザーバと言う機能があります。 example.swift struct Practice { // ストアドプロパティ var training = "push ups" { willSet { //プロパティ変更前の値 print("Yesterday's training is \(self.training).") } didSet {//プロパティ変更後の値 print("Now training is \(self.training)") } } func CallTraining() { print("Training \(self.training)") } } var practice = Practice() practice.CallTraining()//Training push ups practice.training = "Squat" practice.CallTraining() //↑ //Yesterday's training is push ups.(willSet) //Now training is Squat(didSet) //Training Squat (CallTraining) willsetでプロパティが変更する前の値を確認できます。 didSetでプロパティが変更後の値を確認することができます。 コンピューテッドプロパティ コンピューテッドプロパティは、値を計算するプロパティの事を指します。 {}の後に、getを使ってゲッタとsetを使用したセッタを定義して使うことができます。 example.swift struct Muscle { var weight = 30 var Training: String { // ゲッタを定義 get { if weight >= 40 { return "Perfect!!" } return "Good!!" } // セッタを定義 set { print(newValue) } } } var MuscleTraining = Muscle() let FirstTraining = MuscleTraining.Training print(FirstTraining)//Good!! MuscleTraining.weight = 50 let SecondTraining = MuscleTraining.Training print(SecondTraining)//Perfect MuscleTraining.Training = "Oh My God!!!"//Oh My God!!! 定義される対象により分類されるプロパティ 定義される対象により分類されるプロパティには主に三つが挙げられます。 インスタンスプロパティ タイププロパティ クラスプロパティ では順番に述べていきます。 インスタンスプロパティ インスタンスを宣言して使用するプロパティをインスタンスプロパティと呼びます。 example.swift struct Power { //インスタンスプロパティ var weight = 30 } var MyMuscle = Power()//インスタンスの宣言 print(MyMuscle.weight)//30 print(Power.weight)//エラー タイププロパティ タイププロパティは型そのものに紐付いているプロパティです。 example.swift struct Power { //インスタンスプロパティ var weight = 30 //タイププロパティ static var training = "PushUp" } var MyMuscle = Power() print(MyMuscle.weight)//30 print(Power.training)//PushUp インスタンスを宣言しなくても、型にあるタイププロパティを使うことができます。 クラスプロパティ クラスプロパティは、クラスに紐ずくプロパティのことです。 クラスで共通の値を使いたい時に利用します。 example.swift class Power { var weight = 30 class var training: String { return "PushUp!" } } print(Power.training)//PushUp! 参考文献 公式ドキュメント qiita文献 参考にさせていただきました。 ありがとうございます。 まとめ 種類多すぎてパンクしました。
- 投稿日:2021-12-30T11:39:40+09:00
動画にバーチャル背景をつけることはできるのか? → SemanticImageでかんたんに
撮影済みの動画にバーチャル背景をつける方法 既に存在している動画にバーチャル背景をつけられれば、 面白い編集ができる。 バーチャル背景はリアルタイムでしかつけられないのか? バーチャル背景は撮影時に設定するものが多い。 既存の動画を処理したい。 しかし、動画の処理を書くのは大変そう。 SemanticImageで秒で解決 SemanticImageというライブラリなら、 かんたんに既存の動画にバーチャル背景を適用できる。 使用方法 1、SemanticImageをインポートする SwiftPackageManagerでSemanticImageを追加する。 import SemanticImage 2、背景合成を実行 sematicImage.swapBackgroundOfPersonVideo(videoURL: url, backgroundUIImage: uiImage, { err, processedURL in // 処理済み動画URLをここで使う }) ? フリーランスエンジニアです。 お仕事のご相談こちらまで 簡単な開発内容をお書き添えの上、お気軽にご連絡ください。 rockyshikoku@gmail.com Core MLやARKitを使ったアプリを作っています。 機械学習/AR関連の情報を発信しています。 Twitter Medium
- 投稿日:2021-12-30T00:03:48+09:00
Swift ユニットテスト とことんシンプルなテスト導入
初めてのQiita投稿です。 間違いあればコメントいただけると幸いです。 よろしくお願い致します。 Xcode 13.1 プロジェクト作成 Include Testsにチェックを入れてプロジェクトを作成します。 UnitTest, UI UnitTestのファイルがデフォルトで生成されます。 ViewControllerにテスト対象のメソッドを追加 下記メソッドをViewControllerへ追加します。 func add(num1: Int, num2: Int) -> Int { return num1 + num2 } Tests.swift内にテストを追加 下記テストを追加 // testを行う場合は関数名の頭にtestと記述 func testAdd() throws { // ViewControllerをインスタンス化 addメソッドに引数1と3を与えてresultにInt型の結果を代入する let result = ViewController().add(num1: 1, num2: 3) // XCTAssertEqualは引数2つが等しいかテストを行う 等しい場合テストが成功する XCTAssertEqual(result, 4) } テストを行う 赤枠のボタンを押下します。するとテストが走り、失敗なら警告、成功なら緑のマークが表示されます。 これでテストは完了です。私自身、食わず嫌いでテストを避けていましたがシンプルに実装することで簡単に出来ました。 これから あえてテストを失敗させるためにメソッドの内部を変更したり、XCTAssertEqualの第2引数を変更してみたり、さまざまな箇所を変更して結果を確認してみましょう。XCTAssertEqual()以外にもいくつものテストがあるので調べながら試してみましょう。 既にあるプロジェクトへのテストの追加やUIテストなどありますが、とことんシンプルに説明できたのではないかと思います。 以上、最後までご覧いただきありがとうございました。
- 投稿日:2021-12-30T00:03:48+09:00
Swift ユニットテスト 5分で出来るとことんシンプルなテスト導入
初めてのQiita投稿です。 間違いあればコメントいただけると幸いです。 よろしくお願い致します。 Xcode 13.1 プロジェクト作成 Include Testsにチェックを入れてプロジェクトを作成します。 UnitTest, UI UnitTestのファイルがデフォルトで生成されます。 ViewControllerにテスト対象のメソッドを追加 下記メソッドをViewControllerへ追加します。 func add(num1: Int, num2: Int) -> Int { return num1 + num2 } Tests.swift内にテストを追加 下記テストを追加 // testを行う場合は関数名の頭にtestと記述 func testAdd() throws { // ViewControllerをインスタンス化 addメソッドに引数1と3を与えてresultにInt型の結果を代入する let result = ViewController().add(num1: 1, num2: 3) // XCTAssertEqualは引数2つが等しいかテストを行う 等しい場合テストが成功する XCTAssertEqual(result, 4) } テストを行う 赤枠のボタンを押下します。するとテストが走り、失敗なら警告、成功なら緑のマークが表示されます。 これでテストは完了です。私自身、食わず嫌いでテストを避けていましたがシンプルに実装することで簡単に出来ました。 これから あえてテストを失敗させるためにメソッドの内部を変更したり、XCTAssertEqualの第2引数を変更してみたり、さまざまな箇所を変更して結果を確認してみましょう。XCTAssertEqual()以外にもいくつものテストがあるので調べながら試してみましょう。 既にあるプロジェクトへのテストの追加やUIテストなどありますが、とことんシンプルに説明できたのではないかと思います。 以上、最後までご覧いただきありがとうございました。
- 投稿日:2021-12-30T00:03:48+09:00
Swift ユニットテスト とことんシンプルなテスト導入方法
初めてのQiita投稿です。 間違いあればコメントいただけると幸いです。 よろしくお願い致します。 Xcode 13.1 プロジェクト作成 Include Testsにチェックを入れてプロジェクトを作成します。 UnitTest, UI UnitTestのファイルがデフォルトで生成されます。 ViewControllerにテスト対象のメソッドを追加 下記メソッドをViewControllerへ追加します。 func add(num1: Int, num2: Int) -> Int { return num1 + num2 } Tests.swift内にテストを追加 下記テストを追加 // testを行う場合は関数名の頭にtestと記述 func testAdd() throws { // ViewControllerをインスタンス化 addメソッドに引数1と3を与えてresultにInt型の結果を代入する let result = ViewController().add(num1: 1, num2: 3) // XCTAssertEqualは引数2つが等しいかテストを行う 等しい場合テストが成功する XCTAssertEqual(result, 4) } テストを行う 赤枠のボタンを押下します。するとテストが走り、失敗なら警告、成功なら緑のマークが表示されます。 これでテストは完了です。私自身、食わず嫌いでテストを避けていましたがシンプルに実装することで簡単に出来ました。 これから あえてテストを失敗させるためにメソッドの内部を変更したり、XCTAssertEqualの第2引数を変更してみたり、さまざまな箇所を変更して結果を確認してみましょう。XCTAssertEqual()以外にもいくつものテストがあるので調べながら試してみましょう。 既にあるプロジェクトへのテストの追加やUIテストなどありますが、とことんシンプルに説明できたのではないかと思います。 以上、最後までご覧いただきありがとうございました。