20201118のiOSに関する記事は6件です。

アクセス修飾子まとめ【Swift】

はじめに

コードを書く際にあまり意識していなかったのと、理解が曖昧だったので備忘録として投稿します。

アクセス修飾子とは?

アクセス修飾子とは、クラスや関数等にアクセス制限を設けるために利用します。

internal

  • 同じモジュール内であればアクセスすることができる。

モジュールとは

モジュールとはimportして読み込んで利用するFrameworkを作成するための仕組み。

private

  • 一番制約の厳しいアクセス修飾子。
  • 同じファイル内からのアクセスのみ許可されている。
  • クラス単位ではなく、ファイル単位のアクセス制御であることに注意がいる。( Swift4からextensionprivateプロパティにアクセスできるようになった。)

fileprivate

  • 同じファイル内からのアクセスのみ許可されている。

public

  • 別のモジュールからでもアクセスできる。
  • 継承やオーバーライドが不可能

open

  • 別のモジュールからでもアクセスできる。
  • 継承やオーバーライドが可能

アクセス修飾子の使い分け

アクセスレベルを特に意識しない場合

  • 何もつけない or internal

アクセスレベルを意識する場合

  • public・・・別のモジュールからも使えるようにしたい
  • open・・・別のモジュールからも使えて、継承やオーバーライドさせたい。
  • private・・・実装を他からは隠したい。
  • fileprivate・・・実装を他からは隠したいが、特定のコード間では共有したい。

補足

fileprivateを使うよりprivateにして、共有したいコードを同じソースファイルにextensionを使ってまとめるほうがいい。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flutter実装時にお世話になったページ 2020/11/18

なにか

毎回、同じ問題に、同じ検索して、同じページで解決してるので。。。

ContainerのBottomにだけ、枠線を入れたかった

Stack Overflow "How to add a border to a widget in Flutter?"

url_launcherでカスタムURLスキーマを使用したアプリ起動ができなかった(Android)

AndroidManifestまで意識が行かなかった。。。

Stack Overflow "[url_launcher] When targeting API 30, canLaunch always retrurns false"

flutter upgradeしたら、ビルド通らなくなった。。。

こんなエラーが出るようになりました。

Flutter Row() 'crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null': is not true. Failed assertion:

Stack Overflow "Flutter Row() 'crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null': is not true. Failed assertion:"

flutter upgradeしたら、Build iOS 失敗するようになった。。。

こんなエラーが出るようになりました。

    ld: symbol(s) not found for architecture armv7
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    note: Using new build system
    note: Planning build
    note: Constructing build description

Stack Overflow "Undefined symbols for architecture armv7 - Failed to build iOS app"

これは、このコマンドで行けるようになったんだけど、Firebaseとかの設定してると色々面倒なので、根本的な原因を確認中、どうやらビルドのターゲットバージョンが問題っぽい。

なんか

Stack Overflowだらけでした。それにしてもStack Overflowのコピーサイトは検索結果を汚染しすぎ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSの言語設定を取得する方法(Swift)

はじめに

iOSの言語設定を取得する方法を紹介します。

環境

PC

  • OS:macOS Big Sur 11.0.1
  • Xcode:12.2 (12B45b)
  • Swift:5.3.1

シミュレータ

  • 機種:iPhone SE (2nd generation)
  • OS:iOS 14.2

結論

  • アプリがローカライズされていない
    • Locale.current ではうまく取得できないので、 Locale.preferredLanguages から Locale を生成し直す
  • アプリがローカライズされている
    • アプリ単位で優先する言語を指定できるので、「おまけ」に書いたようにローカライズの設定を使うのがベター
    • OS単位の言語設定を取得したい場合は、ローカライズされていないときと同様の方法でいい

言語設定の取得を試す

結論に至るまでにいろいろ試したので、過程を紹介します。

PREFERRED LANGUAGE ORDER(使用する言語の優先順序): English > 日本語 (アメリカ)
地域: United States(アメリカ合衆国)

まずはシミュレータのデフォルト設定で試してみます。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["en", "ja-US"]
Locale.current.description en (current)
Locale.current.languageCode en
Locale.current.regionCode nil

ほぼ予想通りの結果ですが、 ja-US という表記を初めて見たのと、 regionCodenil なのは意外でした。

使用する言語の優先順序: 日本語 > English
地域: アメリカ合衆国

次に、使用する言語の優先順序を入れ替えます。
地域は英語→日本語表記になったので変わったように見えますが、変えていません。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["ja-US", "en"]
Locale.current.description en_US (current)
Locale.current.languageCode en
Locale.current.regionCode US

Locale.preferredLanguages が入れ替わったのは予想通りでしたが、他は私の中では予想外でした。
優先順序を入れ替えたことによって「iPhoneの使用言語」が 日本語 に変わったので、 Locale.current.○○ のプロパティも日本になると思いました。

使用する言語の優先順序: 日本語 > English
地域: 日本

使用する言語の優先順序をそのままに、地域を日本に変えます。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["ja-JP", "en-JP"]
Locale.current.description en_JP (current)
Locale.current.languageCode en
Locale.current.regionCode JP

なんかいろいろおかしい気がしますw
シミュレータだからなのか、言語や地域の変更後に再起動していないからなのか、原因はわかりません。
正しい挙動という可能性ももちろんあります。

おわりに

いろいろ試してもよくわかりませんでした。
何となくわかったのが、 preferredLanguages の要素は {languageCode}-{regionCode} で構成されているということです。

iOSの言語と地域について詳しい方がいたら、コメントなどで教えていただけると嬉しいです :relaxed:

追記:
Twitter でAppleの公式ドキュメントを教えていただきました。
言語IDやロケールIDについて詳しく書いてあるので、こちらを読めば深く理解できそうです。
https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15

おまけ:言語設定の取得をローカライズ文字列に任せる

iOSの言語設定がうまく取得できなかったので、代替案を考える必要があります。

Localizable.string"language" = "en"; のようなキーと値を持たせ、言語設定の取得をローカライズ文字列に任せる方法を思いつきましたw
他にいい方法があれば教えてください :sob:

みなさんはアプリ内でなくサーバーから言語設定に応じた文字列を取得する場合、どのように言語設定をサーバーに渡しているのだろう… :thinking:

追記:
@k_katsumi さんにTwitterでいろいろ教えていただきました :pray:

ローカライズされているアプリは、OS単位でなくアプリ単位でも優先する言語を指定できるので、ローカライズの設定に従うのはベターな方法でした。
おまけとして書きましたが、こちらの方法を採用するのがよさそうです。

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSの言語設定を取得するベストプラクティス(Swift)

はじめに

iOSの言語設定を取得するベストプラクティスを紹介します。

環境

PC

  • OS:macOS Big Sur 11.0.1
  • Xcode:12.2 (12B45b)
  • Swift:5.3.1

シミュレータ

  • 機種:iPhone SE (2nd generation)
  • OS:iOS 14.2

結論

  • アプリがローカライズされていない
    • Locale.current ではうまく取得できないので、 Locale.preferredLanguages から Locale を生成し直す
  • アプリがローカライズされている
    • アプリ単位で優先する言語を指定できるので、「おまけ」に書いたようにローカライズの設定を使うのがベター
    • OS単位の言語設定を取得したい場合は、ローカライズされていないときと同様の方法でいい

言語設定の取得を試す

結論に至るまでにいろいろ試したので、過程を紹介します。

PREFERRED LANGUAGE ORDER(使用する言語の優先順序): English > 日本語 (アメリカ)
地域: United States(アメリカ合衆国)

まずはシミュレータのデフォルト設定で試してみます。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["en", "ja-US"]
Locale.current.description en (current)
Locale.current.languageCode en
Locale.current.regionCode nil

ほぼ予想通りの結果ですが、 ja-US という表記を初めて見たのと、 regionCodenil なのは意外でした。

使用する言語の優先順序: 日本語 > English
地域: アメリカ合衆国

次に、使用する言語の優先順序を入れ替えます。
地域は英語→日本語表記になったので変わったように見えますが、変えていません。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["ja-US", "en"]
Locale.current.description en_US (current)
Locale.current.languageCode en
Locale.current.regionCode US

Locale.preferredLanguages が入れ替わったのは予想通りでしたが、他は私の中では予想外でした。
優先順序を入れ替えたことによって「iPhoneの使用言語」が 日本語 に変わったので、 Locale.current.○○ のプロパティも日本になると思いました。

使用する言語の優先順序: 日本語 > English
地域: 日本

使用する言語の優先順序をそのままに、地域を日本に変えます。

Language & Region(言語と地域)
プロパティ 戻り値
Locale.preferredLanguages ["ja-JP", "en-JP"]
Locale.current.description en_JP (current)
Locale.current.languageCode en
Locale.current.regionCode JP

なんかいろいろおかしい気がしますw
シミュレータだからなのか、言語や地域の変更後に再起動していないからなのか、原因はわかりません。
正しい挙動という可能性ももちろんあります。

おわりに

いろいろ試してもよくわかりませんでした。
何となくわかったのが、 preferredLanguages の要素は {languageCode}-{regionCode} で構成されているということです。

iOSの言語と地域について詳しい方がいたら、コメントなどで教えていただけると嬉しいです :relaxed:

追記:
Twitter でAppleの公式ドキュメントを教えていただきました。
言語IDやロケールIDについて詳しく書いてあるので、こちらを読めば深く理解できそうです。
https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15

おまけ:言語設定の取得をローカライズ文字列に任せる

iOSの言語設定がうまく取得できなかったので、代替案を考える必要があります。

Localizable.string"languageCode" = "en"; のようなキーと値を持たせ、言語設定の取得をローカライズ文字列に任せる方法を思いつきましたw
他にいい方法があれば教えてください :sob:

みなさんはアプリ内でなくサーバーから言語設定に応じた文字列を取得する場合、どのように言語設定をサーバーに渡しているのだろう… :thinking:

追記:
@k_katsumi さんにTwitterでいろいろ教えていただきました :pray:

実際に preferredLanguages から Locale を作り直し、各プロパティを確認しました。

print(Locale.preferredLanguages) // ["ja-JP", "en-JP"]

let language = Locale.preferredLanguages.first!
print(language) // ja-JP

let locale = Locale(identifier: language)
print(locale.description) // ja-JP (fixed)
print(locale.languageCode ?? "nil") // ja
print(locale.regionCode ?? "nil") // JP
print(locale.scriptCode ?? "nil") // nil

適切に languageCoderegionCode を取得できました。
自分で生成した Locale だと description の括弧内が (current) でなく (fixed) になるようです。

ローカライズされているアプリは、OS単位でなくアプリ単位でも優先する言語を指定できるので、ローカライズの設定に従うのはベターな方法でした。
おまけとして書きましたが、こちらの方法を採用するのがよさそうです。

@treastrain さんも採用しているとのことです。

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カプセル化について

カプセル化とは

データとメソッドを1つのオブジェクトにまとめてその内容を隠蔽すること!だそうです。
オブジェクト外から直接アクセスすることを出来なくして、不正なアクセス・意図しない変更から守ることができるのです!

オブジェクト指向の1種

オブジェクト指向の構成要素3つのうちの1つになるそうです。
構成要素は以下の3つです。

  • 継承
  • カプセル化
  • ポリモーフィズム

カプセル化するには?

データを保護することがカプセル化です。
その保護をするために、アクセス修飾子と言うものを使ってアクセスを制限していきます。

アクセス修飾子

アクセス修飾子には制限の範囲に合わせて使うものが変わってきます。
以下が一覧になります。
私も使いこなせているわけではないですが。(privateしか使ったことありません)
カプセル化ではprivateを使用します。

  • open モジュール外からもアクセスできる。
  • public モジュール外からもアクセスできる。 サブクラス化されない。 overrideできない。
  • internal モジュール内ならアクセスできる。 デフォルトでこれになっている。
  • fileprivate ファイル内ならアクセスできる。
  • private クラスなど宣言内でしかアクセスできない。(カプセル化に使用)

使ってみた

実際にカプセル化を学ぶきっかけになったコードになります。
tableViewを使用するアプリを作成していて、セルに表示する内容を書くコードだけ別のクラスに書くように指示がありました。
この場合、別のクラスでcheckIconやlabelを使用しようとすると、エラーになります。

class TableViewCell: UITableViewCell {
    //privateを付けることで他のクラスからアクセスできない
    @IBOutlet private var  checkIcon: UIImageView!
    @IBOutlet private var  label: UILabel!

    func configure(isChecked: Bool, name: String) {
        //チェックされているときには表示して、チェックされていない時は表示しないという処理を書く
        checkIcon.image = nil
        if isChecked == true {
            checkIcon.image = UIImage(named: "check")
        }else{
            checkIcon?.image = nil
        }
        label.text = name
    }
}

カプセル化した値は外から変更できないのか?

結論:できます。
そもそもカプセル化とはデータを保護し、異常なデータ変更や意図しない変更を防ぐためにあります。
直接変更しなければ良いのです。
その方法は、関数を使うことです。
1度関数を通せば意図的な変更になりますし、異常な変更を加えるコードであっても、その変更に対応できるコードを関数内に書くことでエラーを防ぐことができるそうです。

カプセル化はオブジェクト指向

データを直接変更するのではなく(バグが発生する可能性があるため)、関数などのオブジェクト自体がデータの変更を行う。これがオブジェクト指向になります。
カプセル化はオブジェクト指向の重要な構成要素になります。

参考サイト

https://jpazamu.com/encapsulation/
https://dev.classmethod.jp/articles/swift3_scoped_access_level/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mac M1(Apple Silicon)でhomebrewをインストールできるの?

今まで通りにインストールしようとしたら...

現状、ターミナルから今まで通りhomebrewをインストールしようとするとこのような出力が表示されます。

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

Homebrew is not (yet) supported on ARM processors!
Rerun the Homebrew installer under Rosetta 2.
If you really know what you are doing and are prepared for a very broken experience you can use another installation option for installing on ARM:
  https://docs.brew.sh/Installation

今まで通りではダメみたいですね。

対策1 ターミナルをRossetaを使用して開くようにする

  • ターミナルの情報を開きます。

image.png

Rosettaを使用して開くにチェック

そうすることでhomebrewのインストールが可能になります。

$ brew doctor

Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: You are using macOS 11.0.
We do not provide support for this released but not yet supported version.
You will encounter build failures with some formulae.
Please create pull requests instead of asking for help on Homebrew's GitHub,
Twitter or any other official channels. You are responsible for resolving
any issues you experience while you are running this
released but not yet supported version.

対策2 /opt/homebrewに保存するように実行する

https://docs.brew.sh/Installation では

However do yourself a favour and install to /usr/local on macOS Intel, /opt/homebrew on macOS ARM, and /home/linuxbrew/.linuxbrew on Linux.

とあります。
macOS ARMでは/opt/homebrewにインストールしてねと案内されています。

実行コマンド

cd /opt
mkdir homebrew
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

まとめ

せっかくのARMなので極力Rosetta使用したくないですよね。
いずれはuniversalに移行するのに...

状況に応じてインストールしましょう!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む