くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

プッシュ通知を処理する

今回はプッシュ通知についてです

プッシュ通知はローカル通知とリモート通知がありますが、今回はリモート通知についてです

簡単にローカル通知とリモート通知の違いを説明すると、ローカル通知はアプリ単体でアプリがフォアグラウンド以外なら通知が表示され、リモート通知は外部のサーバーから端末に対して通知したい場合に使います。主にWebサービスと連携するアプリで使用します

ローカル通知はアプリ単体で通知を表示できるので、実装すれば終わりですが、リモート通知の場合には外部のサーバーから端末に対して通知を行うので、外部サービスとの連携を行う必要があります。

そんなときに便利でよく使うのが、Firebase Cloud Messagingです

Firebase Cloud Messagingとは?

Firebase Cloud Messaging(FCM)について言及する前にiOSのプッシュ通知の仕組みについて説明します

iOSでは、APNsというプッシュ通知のサービスを使い、プッシュ通知を実現します

ドキュメントによると、通知をアプリに送信するサーバーであるプロバイダーからAPNsに送信のリクエストを投げて、アプリに通知を送信するという流れになります

APNSを簡単に補足すると、Push技術を使って常にオープンなIP接続を通してサードパーティ製アプリケーションのサーバーからの通知をアップルの端末に転送します

つまり、iOSアプリでプッシュ通知を実現するためにはAPNsに送信のリクエストを投げるというのが必要になります

では、FCMは何のために必要でしょうか?

FCMはAPNsにリクエストを投げるプロバイダーの役割を果たしてくれます

プロバイダーの役割はサーバーとほとんど同じ意味だと思うので、自前で作ることもできますし、Saasを使うこともできます

その中で、Saasのプロバイダーとして、提供されているのがFCMなんです

FCMは、サーバサイド、クライアントサイド(ここではアプリ)、ともに実装が必要なものの、APIが提供されており、柔軟なプッシュ通知送受信が実現可能なためよく使われています

※間違っていたら指摘してもらえるとありがたいです

FCMを使うために

FCMを使う準備は大まかには2つあります

APNsを使えるようにするための準備とFCMを使うための準備です

APNsを使えるようにするための準備はプッシュ通知用の証明書を作成して、登録することでFCMを使うための準備はFCMのコンソールに対象のアプリの情報を登録するなどです

ここでは詳細な手順は省きますが、自分が参考になった記事を最後に載せますで、ぜひ確認してみてください!!

プッシュ通知を送る処理、受け取る処理

ここからは、実際にプッシュ通知を受け取るための処理と受け取った後の処理について説明していきます

まずは、プッシュ通知を受け取るための処理です

プッシュ通知の許諾ダイアログを表示させる

まずは、アプリを最初に起動したときに表示されるプッシュ通知の許諾ダイアログを表示させるための処理です

import UIKit
import UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 

        UNUserNotificationCenter.current().delegate = self
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { _, _ in
        })

        application.registerForRemoteNotifications()

        return true
    }
}

これでプッシュ通知を許可するかどうかのダイアログを表示させます

FCMの処理を追加する

まずはPodfileに下記を追加してインストールしましょう

pod `Firebase/Core`
pod `Firebase/Messaging`

次にFirebaseの初期化とFCMのdelegateを使うための処理を記載します

didFinishLaunchingWithOptions launchOptionsで行います

import UIKit
import UserNotifications
import Firebase
import FirebaseMessaging

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 

        FirebaseApp.configure()

        Messaging.messaging().delegate = self
    }
}

FCMのdelegateメソッドは下記になります

extension AppDelegate: MessagingDelegate, UNUserNotificationDelegate {

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { 

        // トークンをアプリケーション サーバーに送信する処理
    }
}

上記の処理は登録トークンを取得するための処理です

このメソッドは通常、登録トークンを使用してアプリが起動するごとに 1 回ずつ呼び出されます

そのトークンを使ってどのデバイスにプッシュ通知を送るのかを判別するために使います

FCMの公式ドキュメントによると、下記のように記載があります

FCM SDK は、FCM登録トークンに対する APNs トークンのマッピングと、ダウンストリーム メッセージのコールバック処理中のアナリティクス データの取得という 2 つの主要領域で、メソッドの実装入れ替えを行います

つまり、FCMを使う場合にはFCMトークンを使い、FCMを使わない場合には別のトークンを使うことになります

トークンをアプリケーション サーバーに送信する処理はAPIで行う場合が多いと思うので、今回は割愛します

プッシュ通知を受け取った後の処理

プッシュ通知を受け取ったら、下記の処理が実行されます

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHanfler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { 
    }
}

上記のuserInfoペイロードの値が入っているはずなので、その後の処理を行ってください

プッシュ通知の準備段階での必要な手順の参考記事

【Swift5】リモートプッシュ通知の実装方法

↑だけでも十分準備ができるくらいいい記事です

バックグラウンド iOS アプリにテスト メッセージを送信する

Firebaseは公式ドキュメントが理解しやすいです

プッシュ通知の確認は下記のライブラリを使えば簡易的に確認できます

github.com

UITabBarControllerについて

iOSの開発では必須といっていいくらいUITabBarControllerは使うと思います

今回はそんなUITabBarControllerについて記載しようと思います

UITabBarControllerはstoryboardで作成する方法とコードで実装する方法があるので両方説明しようと思います。(個人的にはコード派です)

storyboardでの作成

まずはstoryboardで作成する方法です。

プロジェクトを作成したら、ViewControllerを選択した状態で、EditorでEmbed In → TabBarControllerを選択します

f:id:kumaskun:20210211213918p:plain

TabBarControllerを選択したら下記のようにTabBarが追加されていると思います

f:id:kumaskun:20210211214045p:plain

この状態だとTabBarのメニューは1つなので、メニューを追加します

ちなみにTabBarの表示できる個数は5つまでで、Human Interface Guidelinesによると、3〜5個が理想のようです。

新しくViewControllerを追加して、最初に作成したViewControllerを選択した状態で新しく作成したViewControllerへ伸ばすといくつかの選択肢が現れます

そこからview controllersを選択します

f:id:kumaskun:20210211214753p:plain

すると、下記のようにメニューが2つになります

f:id:kumaskun:20210211214951p:plain

メニューの名前やイメージ画像などはそれぞれのメニュー画面から変更でき、TabBarの設定変更(背景色変更など)はTabBarControllerからできます

f:id:kumaskun:20210211215539p:plain

コードでの実装

UITabBarControllerの画面を作成している場合には実装で作成するクラスと紐付ける必要があります(画面自体を作成しない場合には必要ないです)

f:id:kumaskun:20210211215923p:plain

まずは、メインとなるUITabBarControllerを継承したクラスを作成します

import UIKit

class MainTabBarController: UITabBarController {
    
}

次に表示させたいメニューのクラスを作成します

表示させたいメニューのクラスはUIViewControllerを継承します

import UIKit

class FirstMenuViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}
import UIKit

class SecondMenuViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}

そして、UITabBarControllerのクラスファイルにタブとして表示させたいViewControllerを定義します

class MainTabBarController: UITabBarController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var menuViewControllers: [UIViewController] = []
        
        let firstMenuViewController = FirstMenuViewController()
        let secondMenuViewController = SecondMenuViewController()
        
        menuViewControllers.append(firstMenuViewController)
        menuViewControllers.append(secondMenuViewController)
        
        self.setViewControllers(menuViewControllers, animated: false)
    }
}

self.setViewControllers(viewControllers, animated: false)viewControllers = menuViewControllersでも可能です

UITabBarControllerはviewControllersというプロパティを持っているためそこにメニュー群の情報(ここでのmenuViewControllers)を代入してあげればいいです

もう一歩

UITabBarControllerを継承したクラスはアプリを起動したときに最初に表示される基底となる場合が多いと思います

なので、AppdelegateのdidfinishLaunchingWithOptionsなどで下記のように定義することが多いと思います

let controller = MainTabBarController()

window?.setRootViewControllerAnimated(controller, completionHandler: {
})

storyboardを使った方法だと画面遷移がわかりやすい反面、UITabBarControllerの画面を作らないといけないのが手間な気がします

UITabBarControllerはソースコードで作成して、メニューのControllerをstoryboardで作成するのが個人的にはおすすめです!

また、個人的にはまったのがUITabBarControllerのライフサイクルです

TabBarのアイテムが2つある画面を想定して説明します

・初回起動(1つめの画面)
1つめのitem: viewDidLoad()
1つめのitem: viewWillAppear()
1つめのitem: viewDidAppear()

・TabBar : 2つ目のボタンタップ
2つ目のitem: viewDidLoad()
2つ目のitem: viewWillAppear()
1つめのitem: viewWillDisappear()
1つめのitem: viewDidDisappear()
2つ目のitem: viewDidAppear()

・TabBar : 1つ目のボタンタップ
1つめのitem: viewWillAppear()
2つ目のitem: viewWillDisappear()
2つ目のitem: viewDidDisappear()
1つめのitem: viewDidAppear()

上記からわかるように、TabBarのアイテムは初期表示されれば、再度表示してもviewDidLoad()は行われないので、注意が必要です!

参照

UITabBarControllerの使い方

Retrofitの基本的な使い方

今回はRetrofitの基本的な使い方について書きたいと思います。

Android開発でAPI連携を行う場合に必ずと言っていいほど使うと思います。たまにハマってしまうので、まとめようかと思います。

Retrofitは、APIから取得するJSONデータを、オブジェクトにしてアクセスできるようにするまでを面倒見てくれるHTTP clientです。

通信はOkhttpというライブラリを合わせて使うことが多いと思います。今回はOkHttpの説明は省きたいと思います。

では使い方をみていきましょう!!

Retrofitの使い方

使い方はかなりシンプルです。

  1. gradleでの設定追加
  2. Interface実装
  3. HttpClient実装

gradleの設定追加に関しては下記自分が書いた記事をみてください!

RxjavaとRetrofitで非同期通信を行う

今回は2の「Interface実装」を少し詳しくみていきます。

リクエストメソッド

下記が1番シンプルなパターンです。

@GET("api")
val api(): Call<Response>

上記の場合だと、実行されるAPIは「http://○○○○○○○○○○○○○○○○/api」という形になります。ここでは説明を省いてましたが、URLのapi以前はHttpClient実装で定義することが多いと思います。

@GETをつけることでGETメソッドであることを明示します。

また、下記のように直接パラメータをつけることも可能です。

@GET("api/list?sort=desc")
val api(): Call<Response>

URLを動的に扱う

URLを動的に扱う場合は下記のようにします。

@GET("api/{id}/list")
fun getList(@Path("id") groupId : Int) : Call<Response>

{}で囲んで命名し、@PathをNameと一緒に定義することで渡したパラメータがURLパスの中に代入されます。 今回の場合はidを動的にしてURLでその値を受け取ってリクエストを作ります。

また、@Pathの他に@Queryというものもあります。

@GET("api")
fun getList(@Query("id") groupId : Int) : Call<Response>

こうするとAPIのURLは「http://○○○○○○○○○○○○○○○○/api?id=○○」になります。後ろにをつけてパラメータを追加する形になります。 GETリクエストで多い形式です。

リクエストボディ

先ほどのURLの末尾にをつけてパラメータを追加する物とは別に、インスタンスがもつ要素をJson形式に変換してパラメータに追加する形式があります。 その場合はインスタンスクラスを引数にするインターフェースを用意し、@Bodyをつけます。

これはPOSTやPUTなどでよく使われます。

場合によりますが、GETとPOSTで@Bodyを使うか@Queryを使うか変わってくるので確認しましょう!これで自分は苦労しました。(今回はこれが理由で記事書いてます)

@POST("users/create")
fun createUser(@Body user: User): Call<Response>;

RetorfitではHeaderを定義するることもできます。

@Headers({
    "Accept: application/json",
    "token: AAAAAAA"
})
@GET("api")
val api(): Call<Response>

単体指定、複数指定も可能です。ただ、動的な値を指定する場合は悪鬼のようにするかOkHttpのIntercepterで動的に作成することになると思います。

@GET("api")
val api(@Header("token") token: String): Call<Response>

// もしくはマップ形式で渡すことも可能
@GET("user")
val api(@HeaderMap Map<String, String> headers): Call<Response>

FORM ENCODED

application/x-www-form-urlencoded (key=value) 形式に自動で変換して欲しい場合は@FormUrlEncoded@Filedを使います。

@FormUrlEncoded
@POST("user/edit")
val updateUser(@Field("first_name") firstName :String, @Field("last_name") lastName :String): Call<Response>

@FormUrlEncodedUTF-8エンコードしてしまうので、他の文字コードで POST する必要がある場合は@Bodyを使う必要があります。

MULTIPART

Retrofitは画像やファイルなどマルチパートなデータ送信にも対応しています。 次のように@Multipartをつけ、送りたいデータには@Partあるいは@PartMapをつけます。

@Multipart
@PUT("user/photo")
fun updateUser(@Part("photo") photo: RequestBody): Call<User>

ただ、@Multipart@FormUrlEncodedはContent-Typeが矛盾するので併用できません。

HttpClient実装

最後にHttpClientの実装についても軽く触れます。 Retrofitのフレームワークを使い、APIを定義したInterfaceをインスタンス化します。

val retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

val service = retrofit.create(GitHubService.class)

このserviceがInterface(APIを定義したもの)であり、実際にAPIコールを行う際に利用します。

また、RetrofitではhttpClientの実装としてokhttpを使用するのが一般的ですが、自分でOkHttpのインスタンスを指定することが出来ます。

val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(new HttpLoggingInterceptor().setLevel(Level.BODY))
        .build();

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
 .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

val service = retrofit.create(GitHubService.class)

今回はログ出力の設定を入れているだけですが、ヘッダーの設定やその他いろんな設定を加えることができます。

Gsonについて

HttpClient実装でGsonConverterFactory.create()というファクトリーメソッドを設定しました。
今回Gsonを使用するので、ファクトリーメソッドを設定しないとJSONをオブジェクトに変換できないためです。

ここでGsonについて補足しようと思います。

Gsonは、Googleが提供するJSONデータとオブジェクトを相互に変換するためのライブラリです。 具体的には、JSONデータをレスポンスのクラスにマッピングした状態に変換するときに使用するクラスです。

オブジェクトをマッピングする場合には次のようにして使用します。

data class TestData(
    var firstName: String,
    var secondName: String
)

val strJson = "{firstName=A, secondName=B}"
val testData = Gson().fromJson(strJson, TestData::class.java)
val firstName = testData.firstName

リストをマッピングする場合には次のように使用します。

val strJson = "[{firstName=A, secondName=B},{firstName=AAA,secondName=BBB}]"
val listType = object : TypeToken<List<TestData>>() {}.type
val testDataList = Gson().fromJson<List<TestData>>(strJson, listType)
val firstName = testDataList[0].firstName

実際にAPIで使用する場合にはマッピングするクラスを指定すればいいだけなので、上記のような処理は基本的には行わないですが、 Jsonのレスポンスをマッピングする場合には上記のようにしてマッピングをするというのを覚えておくといいかもしれません。

参照

Retrofit公式ドキュメント

Android Retrofit2 with Kotlin

iOSのシミュレーターにプッシュ通知を送る

今回はプッシュ通知のテストについて書きます。

プッシュ通知のペイロードはわかっていてもプッシュ通知の機能がまだない場合ありませんか?

業務でたまたま発生してプッシュ通知のテストがシミュレーターでできることを知ったので方法をまとめたいと思います。

前提としてApple Push Notification Service payloadという以下のようなフォーマットのJSONファイルが必要になります(拡張子は .apnsのファイル)

{
    "aps":{
        "alert":"これはテストです",
        "sound":"default",
        "badge":1
    }
}

JSONファイルをシミュレータにドラッグアンドドロップ

この方法が1番簡単だと思います。

Simulator Target BundleにプロジェクトのBundle IDを入力します

他にペイロードのデータなどはプロジェクトによって追加してください

{
    "Simulator Target Bundle": "",
    "aps":{
        "alert":"これはテストです",
        "sound":"default",
        "badge":1
    }
}

上記のようなapnsファイルをシミュレータにドラッグアンドドロップすればプッシュ通知をシミュレーターに送ることができます

コマンドラインで送る

下記のようにsimctlを使う方法もあります。この場合Simulator Target Bundleは不要です

$ xcrun simctl push <シミュレーターのDeviceID> <BUNDLE_ID> <APNS_FILE_NAME>

SIMULATOR_DEVICE_ID は次のコマンドで調べることができます。

xcrun simctl list

作成したapnsファイルをもとにプッシュ通知がシミュレーターに送られるはずです

apnsファイルを作成する際に"aps"はないとうまくいかないと思うので、注意してください

UITableViewでカスタマイズヘッダーを使う

しばらく更新していないうちに年を越してしまいました。。。。。

これからはなるべく更新していく予定です

今年初の記事はUITableViewでカスタマイズヘッダーを使う方法です

UITableViewではstoryboardで作成することができるのですが、下記のようにヘッダーやフッダーをカスタマイズが難しいです。

f:id:kumaskun:20210208001930p:plain
storyboardでのヘッダー・フッター作成イメージ

では、カスタマイズする場合にはどうするかを説明したいと思います。

レイアウトをxibで作成

まずは下記のようにレイアウトをxibファイルで作成します

f:id:kumaskun:20210208225933p:plain

気をつけないといけないのは、デフォルトではiPhoneサイズのViewになっており変更もできないので、sizeをFreeFormにしないといけないということです

そして、Custom Classを対応するクラスに設定しましょう

f:id:kumaskun:20210208230232p:plain

セクションヘッダー(xibファイル)をUITableViewに登録する

override func viewDidLoad() {
  super.viewDidLoad()
  let nib = UINib(nibName: "HeaderView", bundle: nil)
  tableView.register(nib, forHeaderFooterViewReuseIdentifier: "HeaderView")
  tableView.sectionHeaderHeight = 40
}

xibファイルでカスタムし、使用できる状態にします

"HeaderView"の箇所は先ほど作成したクラス名を定義します

tableView.sectionHeaderHeightでセクションヘッダーの高さを一律に設定します

UITableViewDelegateheightForHeaderInSectionでセクション単位で変更する方法もありますが、今回は一律に設定します

セクションヘッダーを独自ビューで生成する

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView")

        return view
    }
}

UITableViewDelegateviewForHeaderInSectionで定義します

dequeueReusableHeaderFooterViewを使ってID指定で取り出します。

フッターを作成する場合にはtableView(_:viewForFooterInSection:) -> UIView?で定義します

ヘッダーやフッターをカスタマイズする場合は多いと思うので、参考になれば幸いです!!

エミュレーターでネットに接続する

今回は小ネタです。

以前、エミュレーターでインターネットに接続できずなぜ?と思ったことがあります。

デフォルトでAndroid WifiというWifiに接奥されていますが、設定をしないとインターネットに接続できないようです。 早速みていきましょう!

まずはエミュレーターがあるパスに移動しましょう。

preferenceからAndroid SDKのパスを確認しましょう。

f:id:kumaskun:20201111233451p:plain

ほとんどの場合、下記の場所に置いてあるはずです。

cd /Users/xxx/Library/Android/sdk/emulator

次に使用できるエミュレーターを確認します。

./emulator -list-avds

すると、下記のように一覧が表示されます。

Nexus_5X_API_29
Pixel_2_XL_API_29

そして、下記コマンドで起動するとインターネットに接続できます。 Nexus_5X_API_29の箇所は一覧に表示された名前で変更すると変更したエミュレーターで起動できます。

./emulator -avd Nexus_5X_API_29 -dns-server 8.8.8.8

小ネタですが、1時間くらいハマったので忘れないようにしなきゃと思いました。

Contextについて

今回はAndroidでよく出てくるContextについて説明しようかと思います。

ContextはAndroidでよく出てくると思うのですが、漠然としたものでフワフワしていたので、少し調べてみました。

Contextとは?

Contextを公式で確認すると下記のような記載があります。

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

Android OS の環境やリソースへのアクセスの窓口となるコンポーネントです。 データベースやファイル、アプリで利用する画像データなどへのアクセスの窓口となるほか、他のアプリとの連携や、アプリ情報へのアクセスの窓口ともなります。 よく使うのはリソース取得、Activityの起動、intentの送受信などかなあと思います。 また、Context はライフサイクルを持っていて、 端末の様々な 状態遷移の管理も、Contextが行います。

Contextはいくつかの種類が存在します。アプリを作る際には、 どの種類のContext かを意識する必要があります。

Contextの種類

  • Application:Android アプリ全体を統括します。 アプリケーションが起動してから終了するまでのライフサイクルを管理します。シングルトンなので、1つしかないです。
  • Activity:1つの画面を統括します。MVC モデルの、コントローラに相当する役割を担います。 1つの画面が構成され、バックグラウンドに移るか、終了するまでのライフサイクルを管理します。
  • Service:画面を持たず、バックグラウンドで動作します。 バックグラウンドで常に動き続ける常駐型の Service と、都度起動と終了をする Service の2種類があります。 Service が作られてから終了するまでのライフサイクルを管理します。

Contextの取得

Contextを取得することがよくあると思います。大まかには下記のようにして取得します。

  1. Activityのthis
  2. ActivityやApplicationのgetApplicationContext
  3. ViewやFragmentのgetContext

1は特になじみのある方が多いと思います。1はthis@MainActivityのようにすることもできます。

this@にするパターンは下記の例の場合です。

class A {
    inner class B {
        fun Int.foo() {
            val a = this@A
            val b = this@B

            val c = this
            val c1 = this@foo
        }
    }
}

上記の場合はthisはInt foo()のレシーバーであるIntになります。

なので、スコープ外にあるAやBを取得する場合にはthisをつけます。

ここで注目したいのはActivityでContextを取得する場合はthisgetApplicationContextの2つの方法があるということです。

どちらを使っても良さそうで、しかもgetApplicationContextはnullにならないので、ActivityでgetApplicationContextを使おうと思う方もいるかもしれません。

ただ、その場合は意図しない挙動になったり、下手したらメモリリークを引き起こす可能性もあるということを頭に入れておかないといけません。

まず、getApplicationContextの場合はAndroidManifest.xmlに設定したテーマが参照され、thisの場合はAndroidManifest.xmlのに設定したテーマが参照されるかという違いがあります。

そして、常にApplicationContextの方を参照してしまうと意図しないView(標準ダイアログなど)に割り当てられたり、メモリリークの原因となる可能性があります。

QA Stackというサイトに下記のパターン別取得方法が載っていたので、参考になるかもしれません。

f:id:kumaskun:20201108195620p:plain
パターン別Context取得推奨方法

この表をみると基本的にはライフサイクルに従うものはActivityで取得すべきなので、thisを使い、AlpplicationにまたがるものはgetApplicationContextがいい気がします。

例えば、AlertDialogは専用のクラスを作る場合が多いかもしれませんが、表示させるのはActivityでの画面の上なはずです。 そうすると、ライフサイクルに従った方が合理的な印象はあります。

ただ、この辺りは諸説いろいろあるため、いろんな意見を聞いてみたいです!!

自分はこうしているなどあればコメントしてくださると嬉しいです!!

参照

Kotlin リファレンス

getContext()、getApplicationContext()、getBaseContext()と“ this”の違い

Android:引数はthisか?getApplicationContextか?ActivityとApplicationの違い

Xcodeのショートカット集

今回はXcodeのショートカットをまとめようかと思います。

なぜ、この記事を書こうかと思ったのかというと、ショートカットを使うことで開発が効率的に進められることを体感したからです。

最近、ペアプロを体験して、相手の開発をみる機会がありました。 そこで、ショートカットを使うことでこんなにも差があるのかと感じたので、使おうと思いました。

ただ、Xcodeのショートカットをあまり知りませんでした。 むしろ、そんなにショートカットは充実していないと思い込んでいましたが、調べてみるとそれなりに充実していたので、参考用にまとめようと思います。

ビルド・実行のショートカット

結構無意識で使っているコマンドが多いかもしれないですが、載せます。

操作 コマンド
ビルド Cmd + B
実行 Cmd + R
クリーンビルド Cmd + Shift +K
起動しているアプリの終了 Cmd + .
一時停止・再開 Cmd + Control + Y
ブレークポイントの追加・削除 Cmd + \
ステップオーバー F6
ステップイン F7
ステップアウト F8

検索

これは他のIDEでもありますし、よく使う方も多いと思います。

操作 コマンド
ファイル内検索 Cmd + F
フォルダ内検索 Cmd + Shift + O
プロジェクト全体の検索 Cmd + shift + F
ファイル内のメソッド一覧表示と検索 Control + 6

ウィンドウ操作

個人的にはこの辺りはあまり知らなくて、知ってたら1番効率化できそうだと思っている箇所です。

操作 コマンド
ナビゲーターエリア(左側のファイル一覧とか)の表示・非表示 Cmd + 0
ユーティリティエリア(右側の制約を設定したりする箇所)の表示・非表示 Cmd + Option + 0
デバッグエリア(コンソールログとか)の表示・非表示 Cmd + Shift + Y
タブの追加 Cmd + T
左上ナビゲーターエリアのメニューの移動 Cmd + 1 (2,3,4としていくと次のメニューに移動する)

コード編集

実装大好きな人は覚えておいて損はないはず!!

操作 コマンド
選択中のクラス・メソッド・変数の定義へ移動 Cmd + Control + J
自動インデント Control + I
編集を一つ進める Cmd + Shift + Z
インデントを1つ下げる Cmd + [
インデントを1つ上げる Cmd + ]
カーソルを行頭へ移動 Cmd + ⬅ or Control + A
カーソルを行末へ移動 Cmd + ➡ or Control + E
カーソルをファイルの先頭に移動 Cmd + ⬆
カーソルをファイルの最後に移動 Cmd + ⬇
右に一単語 移動 Option + ➡
左に一単語 移動 Option + ⬅
ソースを折りたたむ Cmd + Option + ⬅
折りたたんでいるソースコードを展開 Cmd + Option + ➡
カーソルを行頭へ移動 Cmd + ⬅ or Control + A
カーソルを行末へ移動 Cmd + ➡ or Control + E
現在のカーソル位置から行末をまとめて選択 Cmd + Shift + ➡
現在のカーソル位置から行頭をまとめて選択 Cmd + Shift + ⬅
フォント拡大 Cmd + 「+」
フォント縮小 Cmd + 「-」
選択した変数を一括変更 Cmd + Control + E
クイックリファレンス表示 Option + クリック

シュミレーター

シュミレーターをよく使う方は覚えた方がいいかもしれません。

操作 コマンド
左回りに端末を回転 Cmd + ⬅
右回りに端末を回転 Cmd + ➡
ホームボタンクリック Cmd + H
ロック Cmd + L
キーボードの表示・非表示 Cmd + K
Macキーボードへの切り替え Cmd + shift + K
スローアニメーションモードのオンオフ Cmd + T
マルチタスクへ移動 Cmd + H を2回連続
スクリーンショットの取得 Cmd + S
端末を振る Cmd + control + Z

ここまでいろんなショートカットを記載しました。結構な数ありますが、使いこなすと多くの時間を簡略化できる気がします。 ぜひ、使ってみて効率的な開発ライフをお過ごしください!

追記があれば、追記していきます!!