- 投稿日:2020-11-18T23:29:18+09:00
アクセス修飾子まとめ【Swift】
はじめに
コードを書く際にあまり意識していなかったのと、理解が曖昧だったので備忘録として投稿します。
アクセス修飾子とは?
アクセス修飾子とは、クラスや関数等にアクセス制限を設けるために利用します。
internal
- 同じモジュール内であればアクセスすることができる。
モジュールとは
モジュールとは
import
して読み込んで利用するFramework
を作成するための仕組み。private
- 一番制約の厳しいアクセス修飾子。
- 同じファイル内からのアクセスのみ許可されている。
- クラス単位ではなく、ファイル単位のアクセス制御であることに注意がいる。( Swift4から
extension
でprivate
プロパティにアクセスできるようになった。)fileprivate
- 同じファイル内からのアクセスのみ許可されている。
public
- 別のモジュールからでもアクセスできる。
- 継承やオーバーライドが不可能
open
- 別のモジュールからでもアクセスできる。
- 継承やオーバーライドが可能
アクセス修飾子の使い分け
アクセスレベルを特に意識しない場合
- 何もつけない or
internal
アクセスレベルを意識する場合
public
・・・別のモジュールからも使えるようにしたいopen
・・・別のモジュールからも使えて、継承やオーバーライドさせたい。private
・・・実装を他からは隠したい。fileprivate
・・・実装を他からは隠したいが、特定のコード間では共有したい。補足
fileprivate
を使うよりprivate
にして、共有したいコードを同じソースファイルにextension
を使ってまとめるほうがいい。参考
- 投稿日:2020-11-18T22:49:57+09:00
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: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 descriptionStack Overflow "Undefined symbols for architecture armv7 - Failed to build iOS app"
これは、このコマンドで行けるようになったんだけど、Firebaseとかの設定してると色々面倒なので、根本的な原因を確認中、どうやらビルドのターゲットバージョンが問題っぽい。
なんか
Stack Overflowだらけでした。それにしてもStack Overflowのコピーサイトは検索結果を汚染しすぎ。
- 投稿日:2020-11-18T21:27:30+09:00
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
という表記を初めて見たのと、regionCode
がnil
なのは意外でした。使用する言語の優先順序: 日本語 > 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の言語と地域について詳しい方がいたら、コメントなどで教えていただけると嬉しいです
追記:
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
他にいい方法があれば教えてくださいみなさんはアプリ内でなくサーバーから言語設定に応じた文字列を取得する場合、どのように言語設定をサーバーに渡しているのだろう…
追記:
@k_katsumi さんにTwitterでいろいろ教えていただきました当てになるのはpreferredLanguagesで、そこから言語コードだけ、とか分解して取りたいならその値からLocaleを作り直すといいっすよ。
— kishikawa katsumi (@k_katsumi) November 18, 2020
let locale = Locale(identifier:Locale.preferredLanguages[0])
print(locale.languageCode)
print(locale.regionCode)
print(locale.scriptCode)その上で、ケースバイケースで難しいんですけどたいていの場合はユーザーが指定した(望んでいる)ローカライズの設定に従うようにLocalizable.stringを当てにするっていうのはかなりベターな方法だと思います。
— kishikawa katsumi (@k_katsumi) November 18, 2020ローカライズされているアプリは、OS単位でなくアプリ単位でも優先する言語を指定できるので、ローカライズの設定に従うのはベターな方法でした。
おまけとして書きましたが、こちらの方法を採用するのがよさそうです。参考リンク
- Locale | Apple Developer Documentation
- NSLocale | Apple Developer Documentation
- current | Apple Developer Documentation
- preferredLanguages | Apple Developer Documentation
- description | Apple Developer Documentation
- languageCode | Apple Developer Documentation
- regionCode | Apple Developer Documentation
- [iOS]中国語対応のために端末の言語環境の値を取得したときにハマったこと - Qiita
- 言語設定を取得したい場合はLocale.prefferedLanguagesを使う - Qiita
- 投稿日:2020-11-18T21:27:30+09:00
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
という表記を初めて見たのと、regionCode
がnil
なのは意外でした。使用する言語の優先順序: 日本語 > 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の言語と地域について詳しい方がいたら、コメントなどで教えていただけると嬉しいです
追記:
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
他にいい方法があれば教えてくださいみなさんはアプリ内でなくサーバーから言語設定に応じた文字列を取得する場合、どのように言語設定をサーバーに渡しているのだろう…
追記:
@k_katsumi さんにTwitterでいろいろ教えていただきました当てになるのはpreferredLanguagesで、そこから言語コードだけ、とか分解して取りたいならその値からLocaleを作り直すといいっすよ。
— kishikawa katsumi (@k_katsumi) November 18, 2020
let locale = Locale(identifier:Locale.preferredLanguages[0])
print(locale.languageCode)
print(locale.regionCode)
print(locale.scriptCode)実際に
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適切に
languageCode
やregionCode
を取得できました。
自分で生成したLocale
だとdescription
の括弧内が(current)
でなく(fixed)
になるようです。その上で、ケースバイケースで難しいんですけどたいていの場合はユーザーが指定した(望んでいる)ローカライズの設定に従うようにLocalizable.stringを当てにするっていうのはかなりベターな方法だと思います。
— kishikawa katsumi (@k_katsumi) November 18, 2020ローカライズされているアプリは、OS単位でなくアプリ単位でも優先する言語を指定できるので、ローカライズの設定に従うのはベターな方法でした。
おまけとして書きましたが、こちらの方法を採用するのがよさそうです。@treastrain さんも採用しているとのことです。
完全に出遅れてしまったけど、私も各 Localizable.strings に
— treastrain / Tanaka.R (@treastrain) November 18, 2020
"key" = "ja";
"key" = "en";
"key" = "zh-HK";
を書いて、それを拾って判定してる。 https://t.co/2B0BiEZllv参考リンク
- Locale | Apple Developer Documentation
- NSLocale | Apple Developer Documentation
- current | Apple Developer Documentation
- preferredLanguages | Apple Developer Documentation
- description | Apple Developer Documentation
- languageCode | Apple Developer Documentation
- regionCode | Apple Developer Documentation
- [iOS]中国語対応のために端末の言語環境の値を取得したときにハマったこと - Qiita
- 言語設定を取得したい場合はLocale.prefferedLanguagesを使う - Qiita
- 投稿日:2020-11-18T20:52:31+09:00
カプセル化について
カプセル化とは
データとメソッドを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/
- 投稿日:2020-11-18T17:00:14+09:00
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を使用して開くようにする
- ターミナルの情報を開きます。
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に移行するのに...状況に応じてインストールしましょう!