トップ 最新 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|

2018-10-01 [cocoa][swift]MojaveのDark Mode

Macintoshが革新的だったのは、白色背景に黒文字を表示したことだ。これは、macOSのAquaにも受け継がれたのだが、MojaveのDark Mode登場により状況が変わった。説明を信じれば集中したいときはDark Modeが適しているそうだ。

真偽はさておいて、Dark Modeに試してみて感じるのは、Dark Modeに完全対応していないアプリケーションが存在すると、画面が見苦しくなるということ。

今回の発表では、Dark Modeへの対応方法を駆け足で紹介してみる。

lightとdark

システム環境設定で、従来のlightとdarkは切り替えらる。ということは、切り替えに追従して表示を変更できるようにしないといけない、ということになる。

設定

UI Element Colors

ユーザインタフェースに使う色を直接記述してしまうと外観モードの切り替えに対応できないのは当然だ。NSColorではユーザインタフェースのために以下のような色指定を用意している。

  • labelColor
  • controlColor
  • controlBackgroundColor

また、Color Set assetを独自に定義できる。

asset

これを以下のように利用する。

let aColor = NSColor(named: NSColor.Name("MyColor"))

以下は、色の定数を利用した例だ。

override func updateLayer() {
   self.layer?.backgroundColor = NSColor.textBackgroundColor.cgColor
}

2018-10-10 [cocoa][swift]プライバシーとセキュリティ(リモート通知のデバイストークンの扱いなど)

GDPRで話題になる頻度が上がったプライバシーとセキュリティ。対応は個々でだと思うが、サーバを利用しない方が難しい今のスマートフォン・アプリケーション開発者にとって、システム提供側によって、何らかの対応が必要になる可能性がある。そこで、今回の発表では、iOSアプリケーション開発に関係がありそうな項目について取り上げてみた。

GDPRとは

対象は個人情報。内容は、思いっきり端折ると、利用目的など、同意を得ないといけないのと、EEAで得られた情報を第三國へ移転するのは禁止だ。

Appleは

Data and Privacy(https://privacy.apple.com/)というページが用意されているが、これはApple製品向けで、サードパーティの開発者向けの情報でない。

iOS 11.3 で、GDPR相当のプライバシー保護機能を搭載したので、各アプリ/サービスは、個々で判断して対応しろということだろう。

Googleは

GoogleはFirebaseサービスを利用した開発者向けに、Firebase のプライバシーとセキュリティ(https://firebase.google.com/support/privacy/?hl=ja)というページを用意している。

このページでは、Googleの対応内容と開発向けについて説明がある。我々アプリケーション開発者が関係する後者について、ざっと抜き出してみる。

Firebaseの個々のサービスで扱い個人情報は、以下のとおり。

Firebaseサービス 個人情報
Cloud Functions for Firebase IP addresses
Firebase Authentication Passwords
Email addresses
Phone numbers
User agents
IP addresses
Firebase Cloud Messaging Instance IDs
Firebase Crash Reporting Instance IDs
Crash traces
Firebase Crashlytics
Firebase Dynamic Links Device specs (iOS)
Firebase Hosting IP addresses
Firebase Invites Device specs (iOS)
Locally-stored contacts
Firebase Performance Monitoring Instance IDs
IP addresses
Firebase Predictions Instance IDs
Firebase Realtime Database IP addresses
User agents
Firebase Remote Config Instance IDs
Google Analytics for Firebase Mobile ad IDs
IDFVs/Android IDs
Instance IDs
Analytics App Instance IDs
ML Kit for Firebase Uploaded Images

以下について、開発者の対応方法が説明されている。

  • Cloud Messaging
    自動初期化を禁止する(Android)または自動初期化を禁止する(iOS)
    https://firebase.google.com/docs/cloud-messaging/android/client?hl=ja#prevent-auto-init
    https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ja#prevent-auto-init
  • Crashlytics
    オプトイン レポートを有効にする
    https://firebase.google.com/docs/crashlytics/customize-crash-reports?hl=ja#enable_opt_in_reporting
  • Crash Reporting
    オプトイン レポートを有効にする
    https://firebase.google.com/docs/crash/disable-sdk?hl=ja
  • Performance Monitoring
    オプトイン モニタリングを有効にする
    https://firebase.google.com/docs/perf-mon/disable-sdk?hl=ja
  • アナリティクス
    アナリティクスの収集を無効にする
    https://firebase.google.com/support/guides/disable-analytics?hl=ja

この中から、iOSと関係が深いと考えたものについて、もう少し深く調べてみる。

Firebase Cloud Message (FCM) は、iOSのリモート通知に似た位置付けのサービスだ。FCMはインスタンスIDを生成し、それを登録トークンとして利用する。このインスタンスIDが、iOSリモート通知のデバイス・トークンに相当する。このインスタンスIDはアプリケーションをインストールした後にアプリケーションを起動すると自動で生成される。

この良かれと考えて用意した機能が仇になったのか、自動初期化を禁止する方法が用意された。AndroidManifest.xmlに以下の設定を行うと、自動初期化は禁止となる。

<?xml version="1.0" encoding="utf-8"?≶
<application≶
  <meta-data android:name="firebase_messaging_auto_init_enabled"
             android:value="false" /≶
</application≶

例えば、ユーザにクラウド・メッセージの利用を確認してOKとなった場合、以下のコードで自動初期化は有効となる。

FirebaseMessaging.getInstance().setAutoInitEnabled(true);

この有効/無効の設定はシステムによって保持されるので、例えば、ユーザへの確認結果を記録する方法として利用できると考えられる。

ちなみに、現在のインスタンスIDは以下のコードで取得することができる。

FirebaseInstanceId.getInstance().getToken()

これについて、動作確認をして分かったことがあるのだが、正しいのか自信がないため、発表資料では説明しないので、興味がある方は、勉強会で質問してほしい。

上記は、Firebase Cloud Messageの場合だが、iOSのリモート通知のデバイス・トークンも個人情報として、同様な考えて扱うべきだと考えられるので、Firebaseの情報は参考になると思う。

Firebaseはクロスプラットフォームなサービスなので、iOSアプリケーションでも利用している場合があると思うが、今回の件で気をつけないといけないことがある。

Firebaseのアナリティックスは明示的に利用するコードを書かなくても、アナリティックスの収取を行なっている。また、広告IDの収集も行なっている。

Androidで収集を完全に無効にする場合は、AndroidManifest.xmlに以下の設定を行う。

<meta-data android:name="firebase_analytics_collection_deactivated" android:value="true" /≶

Androidで広告IDの収集を無効にする場合は、AndroidManifest.xmlに以下の設定を行う。

<meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" /≶

iOSの場合、Info.plistにFIREBASE_ANALYTICS_COLLECTION_DEACTIVATEDをYESで定義すると収集が完全に無効になる。そして収集を再び有効にするには、この定義を削除すればいいみたいだ


2018-10-15 [cocoa][swift]え!それって参照渡し?

とても違和感を感じる用語がある。それは、『参照渡しだ』。

え!違うだろ?と感じていたが、いい機会なので、調べてみた。

引数

引数と呼ばれるものにどんな種類があるのか、まずは列挙してみる。

実引数

関数に渡す値。

sum(1, 2);

仮引数

関数が受け取った変数。

int sum(int a, int b)
{
    return a + b;
}

値渡し(call by value)

値が渡される。

_ <h2>ポインタ渡し

渡す値がアドレスの値渡し。

参照渡し

  • 変数渡し(call by variable)
    変数そのものを渡す。
  • 参照渡し(call by reference)
    参照渡しで、内部でアドレス情報を渡す方法。

Pascal

Pascalでは,値渡し(call by value)と変数渡し(call by variable)が存在し、変数渡しは参照渡しに相当する。

そもそもは、変数渡しの実装方法に参照渡しがある。参照渡しは、変数に対する参照(アドレス情報)を渡す方法だ。

Inside Macintoshは、コードはPascalで記載されているが、それをC言語で利用する場合、varがついた変数渡しの引数は、C言語ではポインターと読み替えていた。

具体的には、Inside Macintoshで以下のようにPascalで説明されていたとする。

PROCEDURE GetPort(VAR port: GrafPtr);

これをC言語では、以下のように読み替える。

void GetPort (GrafPtr * port);

C言語

C言語の関数の引数は全て値渡し。K&Rでしっかりと説明されている。

ポインタでアドレスの値を渡すのを参照渡しと呼ぶのは間違いだ。

Java

Javaも全て値渡し。

ポインタ演算ができない、アドレス(参照)の値渡しが利用できるが、これを参照渡しと呼ぶのは、如何なものか。

C++

値渡しに加え、本物の参照渡しが存在する。

void time_two(int& a)
{
    a *= 2;
}

また、C++11では右辺値参照・ムーブセマンティクスという所有者の移動が用意されている。

C#

二つの参照渡しの方法が用意されている。

int initializeInMethod = 0;  // 初期化が必須
OutArgExample(initializeInMethod);
Console.WriteLine(initializeInMethod);
 
void OutArgExample(ref int number)
{
    number = 44;
}
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod);
 
void OutArgExample(out int number)
{
    number = 44;  // 代入が必須
}

refは変数が渡されるので、初期化によって値が設定されていない変数はNGだ。

outは値を返すという意味から、初期化は必須でないか、関数内で値を必ず設定しないといけない。

Swift

値渡しだが、inoutキーワードをつけると値呼びの結果返し(call-by-value-result)となる。

C言語のポインターの場合と同様に、変数が参照型の場合、参照の値渡しにより値を変更できる。

class Demo {
    public var num = 0;
}
 
func set999(a: Demo) {
    a.num = 999;
}
 
let demo = Demo()
set999(demo)

値呼びの結果返しの例。

func set999(a: inout Int) {
    a =999
}
 
var num = 0
set999(&num)

トップ 最新 追記