- 投稿日:2021-08-15T15:09:49+09:00
KMMを触ってみて思ったこと
はじめに KMM(Kotlin Multiplatform Mobile)とは、Kotlin/NativeというKotlinのコードをさまざまなOSのネイティブコード(マシン語)に変換する技術を使って、モバイル(iOSとAndroid)に特化したクロスプラットフォーム開発をできるようにするSDKです。 僕はKMMってなんか響きがかっこ良いんでKotlinでiOSアプリが作れるっていうところが凄いなと思って勉強を始めてみました。勉強を始めて一番最初に浮かんだ疑問として、Kotlinで開発するのであればただのAndroid開発と何が違うのかというのがありました。その疑問について色々調べてみました。 仕組みの違い そもそもAndroidのネイティブ開発ではKotlinやJavaを使うことができます。それぞれのコードがART(Android RunTime)という実行環境でAndroidOS上で動くようなネイティブコードにコンパイルされることで動いています。 対してKMMはKotlin/NativeがKotlinを各OSのネイティブコードに変換するための諸々をやってくれているので動くそうです。Kotlin/Nativeの公式ドキュメントの文章を見てみると、 Kotlin/Native is a technology for compiling Kotlin code to native binaries, which can run without a virtual machine. It is an LLVM based backend for the Kotlin compiler and native implementation of the Kotlin standard library. ということらしいです。全然わけがわからないです。色々調べてみたところ、この部分の詳しい説明として↓の記事がありました。 https://developers.cyberagent.co.jp/blog/archives/23149/ 要約すると、Kotlin/Nativeは ・ 標準ライブラリ ・ メモリ管理 ・ プログラムランチャー の3つの機能を提供してくれていることで動くそうです。 なので普通のAndroid開発とKMMでは、最終的にAndroidOS上で動くネイティブコードに変換している点は共通していてそのプロセスが違うということらしいです。 開発する上での具体的な違い まずKMMはマルチモジュール構成となっていて、共有モジュールと各OSのモジュールの三つの構成になっています。各OSのモジュールではそれぞれのOSでしか使えないライブラリ等が使えます。僕はとりあえずサンプルアプリはMVVMで、ViewModelとViewをそれぞれのOS毎に分岐して書くというやり方で作りました。普通のAndroid開発とKMMで開発するときの具体的な実装時の違いとして使えるライブラリの違いがありました。ここがかなり重要な違いかなと思いました。例えば、 HTTPクライアント ・Android -> Retrofit(+ OkHttp) ・KMM -> Ktor client Coroutines ・Android -> coroutines-android ・KMM -> native-mt AAC(Android Architecture Components) ・Android -> 使える ・KMM -> 共有部分のコードでは使えない 他にもあると思いますがこの辺りが違いを実感しました。特にiOSにも対応しないといけないので当たり前ではあるんですが、共有部分のコードでAACが使えないのが辛かったです。ViewModelScope等のAndroidのライフサイクル対応のCoroutineが使えなかったので結局ViewModelを分ける以外にやり方がわかりませんでした。それに関係する話ですが、アーキテクチャに関しても、 ・Android -> MVVMが推奨 ・KMM -> 何が正解か全くわからない といった感じでKMMは何が正解なのかよくわかりませんでした。KMMはそれぞれのOSの違いに対応する時に、どうしてもコードを共通化できない部分が出てきてしまってそれぞれ分岐させなければいけないところがあると思うんですが、その分け方のベストプラクティスみたいなものがわからないです。 感想 とりあえずKotlinでiOSのアプリが作れたのはめちゃくちゃ感動しました。ただ結局ViewModel以降はそれぞれのOS毎に書いているのであんまりクロスプラットフォームで開発している!みたいな実感は湧きませんでした。アーキテクチャ等のベストプラクティスみたいなものがわかればもう少し共通化できる部分が増やせるのかなと思いました。またKMMでの開発を通してAndroid自体の開発に関して少し理解が深まる部分があったのでそれもよかったなと思います。KMM開発においてiOS側からKotlinのflowをobserveする時などもっと具体的な壁もあったのでその辺りもいつか記事に書きたいです。 拙い理解と変な文章の記事をここまで読んでくださってありがとうございました。 参考記事
- 投稿日:2021-08-15T14:12:48+09:00
protocolの基本と種類(swift)
protocolとは 直訳すると議定書・手順。 swiftでは、クラス・構造体などに対してプロパティとメソッドを定義する機能。 プロトコルを適用したクラス・構造体は、プロトコルに定義されているプロパティ・メソッドを必ず定義しなければならない。 つまり、「クラス作成のルールを定めて、それを守らせる」という認識であっているでしょうか。 protocolを定義する sample protocol プロトコル名 { var プロパティ名 : 型 {set get} func メソッド名(引数名 : 型) -> 戻り値の型 } プロパティ名の横には{set get}もしくは{get} を記入する。 {set get} 読み書き可能 {get} 読み込み専用 代表的なプロトコルの種類 CustomStringConvertible インスタンスの文字表現を自由にカスタマイズできるプロトコル。 CustomStringConvertible class Shoe: CustomStringConvertible { let color: String let size: Int let hasLaces: Bool init(color: String, size: Int, hasLaces: Bool) { self.color = color self.size = size self.hasLaces = hasLaces } //ここでインスタンスの文字表現をカスタマイズする var description: String { return "Shoe(color: \(color), size: \(size), hasLaces: \ (hasLaces))" } } let myShoe = Shoe(color: "Black", size: 12, hasLaces: true) let yourShoe = Shoe(color: "Red", size: 8, hasLaces: false) print(myShoe) print(yourShoe) 出力結果 Shoe(color: Black, size: 12, hasLaces: true) Shoe(color: Red, size: 8, hasLaces: false) もしCustomStringConvertibleを使わずに、descriptionも定義しないで出力すると 出力結果(プロトコルなし) Shoe Shoe Equatable 対象が一致するかどうか(イコール)の確認を可能にするプロトコル。 Equable struct Person: Equatable{ var name: String var age: Int //年齢が同じかどうかをBoolで返すメソッド static func == (lhs: Person, rhs: Person) -> Bool{ return (lhs.age == rhs.age) } } //インスタンス化 let yamada = Person(name: "YAMADA", age: 20) let Takahashi = Person(name: "TAKAHASHI", age: 30) //年齢が同じかどうかの確認が可能になる! yamada == takahashi //false Comparable 対象の大小を確認するためのプロトコル。 Equable struct Person: Equatable: Comparable{ var name: String var age: Int //年齢が同じかどうかをBoolで返すメソッド static func == (lhs: Person, rhs: Person) -> Bool{ return (lhs.age == rhs.age) } //年齢が小さいかどうかをBoolで返すメソッド static func < (lhs: Person, rhs: Person) -> Bool{ return (lhs.age < rhs.age) } } //インスタンス化 let yamada = Person(name: "YAMADA", age: 20) let Takahashi = Person(name: "TAKAHASHI", age: 30) //年齢の比較が可能になる! yamada < takahashi //true Codable jsonなどのデータをデコード、エンコードするプロトコル。 Codable struct Person: Codable{ let name = String let height = Int let weight = Int } これだけで、エンコード、デコードともに可能な状態になります。 インスタンス化後に、JsonDecoder/Encoder()などで変換します。 参考文献 App Development With Swift - Unit4 Lesson4.1 _ *本記事は初心者による作成です。細心の注意は払っていますが内容に誤りが含まれる場合がございます。 ご訂正・ご指摘いただけると幸いです。
- 投稿日:2021-08-15T10:52:57+09:00
【iOS14】UITableViewをUICollectionViewに書き換える練習
UITableViewが非推奨の方向らしい? 資料を参考にすれど、む・・・むずかしい。 こういうときは、簡単なサンプルを書いてみようと思い そういう事をされている方の記事を見つけました。 こちらの記事を参考させて頂き、今回はセクションを使わない UICollectionLayoutListConfiguration.Appearance.plain なものを作りたかったので、改変した結果がこちらです。 自分の分かる範囲では、Sectionは完全に消せなかったのでIntにして layoutConfig.headerMode = .none としてみました。 【新しい疑問点】 dataSourceは新しくなったけどdelegateはそのまま? => そのままらしい import UIKit class ViewController: UIViewController { @IBOutlet weak var collectionView: UICollectionView! let data = ["A", "B", "C"] var collectionViewDataSource: UICollectionViewDiffableDataSource<Int, String>! override func viewDidLoad() { super.viewDidLoad() var layoutConfig = UICollectionLayoutListConfiguration(appearance: .plain) layoutConfig.headerMode = .none let layout = UICollectionViewCompositionalLayout.list(using: layoutConfig) collectionView.collectionViewLayout = layout collectionViewDataSource = createDataSource() reloadList() } func createDataSource() -> UICollectionViewDiffableDataSource<Int, String> { let normalCell = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, text) in var content = cell.defaultContentConfiguration() content.text = text cell.contentConfiguration = content } return UICollectionViewDiffableDataSource<Int, String>(collectionView: collectionView) { (collectionView, indexPath, text) -> UICollectionViewCell? in return collectionView.dequeueConfiguredReusableCell(using: normalCell, for: indexPath, item: text) } } func reloadList() { var snapshot = NSDiffableDataSourceSnapshot<Int, String>() snapshot.appendSections([0]) snapshot.appendItems(data) collectionViewDataSource.apply(snapshot) } }
- 投稿日:2021-08-15T07:24:46+09:00
Info.plistからバージョン情報を取得する
バージョン情報の取得方法 VersionNameの場合(1.2.3.4的なやつ) VERSION_NAME=(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" hoge.app/Contents/Info.plist`) echo $VERSION_NAME VersionCodeの場合は、CFBundleShortVersionStringをCFBundleVersionに置き換える。