woshidan's blog

あいとゆうきとITと、とっておきの話。

iOSのProvisioning Profile周りについてざっくり確認するシートを作りました

iOSのProvisioning Profile周りについて毎回ハマっているような気がしていたので、どのファイルをいつ用意して用意した後どうすればいいのか、といったことを手短に確認するために

  • 主になんて呼ばれているか
  • 代表的なファイル名
  • 主にいつ作成するか、どう作成するか
  • ファイルをDLするか、DLした後どうするか
  • XCode上でそのファイルに関連してどう設定するか
  • そのほか備考

をまとめて、作成する際に必要、など関連のあるところの線を引いた図を作ったので貼ります。

f:id:woshidan:20170331174938p:plain

上の図に千鳥足みたいなのありますが、一つのファイルに対して他方のファイルが複数存在するといった場合は複数存在する方が雑に鳥足みたいにしました。 なんかそういうツールや様式があった気がしますが、それは次の機会ということで。

参考

https://i-app-tec.com/ios/provisioning-profile.html http://macdays.hatenablog.com/entry/2013/10/11/172532 http://qiita.com/edo_m18/items/6f10e57f95b25d9dab4e http://qiita.com/fujisan3/items/d037e3c40a0acc46f618

注釈

※1 Apple Developer Centerに登録した1つのチームから複数の開発者を招待して、その開発者はそれ以外のチームに所属していないという想定。個人開発している人もいるのでいつも事実では無いですが会社アドレスのアカウントでは事実なこと多いのでは
※2 証明書周りがよくわからなくなってむやみやたらに再発行され各種ファイルの作り直しに励むのはよくあるので助けてください
※3 1つのアプリについてProductionとSand Boxというつもり。

気になるところあったらツッコミください。

ObjCで戻り値以外にNSErrorのポインタを出しているのが面白かった話

NSErrorの使い方というよりはNSErrorが使われる場面についての話で、 C言語をはじめとした関数やメソッドの戻り値は基本的に1つになります。

複数の値を返したい場合、構造体を作ったり、オブジェクトを使ったり、といった方法がありますが、基本的にメソッドの戻り値は1つの値か、関連する値をまとめた一つのオブジェクト、となります。

普段はそこまでこまらないのですが、本来の処理と全然関係ない情報を呼び出し元に返したくなった場合はどうしたらよいでしょうか。例えば、エラーが起きてしまって本来の値が返せない、といった場合。

JavaRubyなら上記のような想定外の事態が起きて処理が進められない場合には例外を投げてしまえばいいのでしょうが、メモリ管理にARCを利用している関係もあり、Objective-Cでは基本的にアプリがそのまま死ぬような場合以外は例外を投げたくありません。

では、どうするか、と言いますと、例外を表すNSErrorのインスタンスのポインタを渡して、何か起きた時にはNSErrorのポインタがさす変数にnil以外が入っているようにするのです。

// 引用元: http://www.inazumatv.com/contents/archives/9078
NSError *error = nil;
NSString *result = [ExampleError exampleMethod:&error]
 
if (error) {
    // error処理
}

// class ExampleError
+(NSString *)exampleMethod:(NSError **)didFailWithError
{
    NSError *error = nil;
    NSString *resultMessage = @"success message";
 
    [self innerMethod:&error];
    if (error) {
        *didFailWithError = error;
        return nil;
    }
 
    return resultMessage;
}

というのが面白かった、というお話。

参考:

iOSでファイルにオブジェクトの状態を保存する/.plistとは

ObjCのコードを読んでいた時に書いたメモを放流。

アーカイブとは

プログラムで使われている複数のオブジェクトを、その属性値や相互の関係も含めてファイルに保存したり、他のプロセスに渡したりしたい場合があります。 そのために、互いに関連するオブジェクトをバイト列に変換する機能をアーカイブといい、さらにバイト列から元のオブジェクトを復元する機能をアンアーカイブといいます。 また、オブジェクトを変換して得られたバイト列をアーカイブと呼ぶことも。

一方、シリアライゼーションはプロパティーリスト程度の単純な階層構造しか表現できません。

アーカイブができるオブジェクトは、NSCodingプロトコルに適合するように実装する必要があります。

// アーカイブ用
- (void)encodeWithCoder:(NSCoder *)coder
{
  [super encodeWithCoder:coder];
  // スーパークラスがNSCodingプロトコルに適合していない場合は不要

  [coder encodeObject:オブジェクト forKey:キー文字列];
  // またはencodedConditionalObject:forKey:を使う

  ...
  [coder encodeDouble:実数の変数 forKey:キー文字列];
  // いくつかの方に合わせたメソッドが用意されている
}
// オブジェクトがまた依存しているオブジェクト...とたどっていくと元のオブジェクトのencode...が
// 呼ばれそうだが、すでにアーカイブされていたら二度目はされないらしい
// アンアーカイブ用
- (id)initWithCoder:(NSCoder *)coder
{
  self = [super initWithCoder:coder];
  // スーパークラスがNSCodingプロトコルに適合していない場合は[super init]でよい

  変数 = [[coder decodeObjectForKey:キー文字列] retain];

  ...
  変数 = [coder decodeDouble:キー文字列];
}

NSKeyedArchiver

上記のencodeWithCoderを使って、対象となるオブジェクトをエンコードした結果をデータオブジェクトに書き込み。 初期化の際は、書き込み先のNSMutableDataのオブジェクトが必要となります。

一つずつアーカイブしていっても良いが、ルートオブジェクトをエンコードすると再起的にオブジェクトグラフがアーカイブ化される。全部完了したらfinishEncodingを読んで後処理をします。

書き込み先はデータオブジェクトなのでデータオブジェクトからファイルへ書き込んだり、他プロセスへ送信したりができるし、ファイルに書き込むまで一括で出来るメソッドもあります。

NSKeyedUnarchiver

上記のinitWithCoderを使って、アーカイブされたオブジェクトが書き込まれたデータオブジェクトからオブジェクトを復元します。 ファイルからデータオブジェクトを作って読み込んだりもできます。

.plist

https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html http://glassonion.hatenablog.com/entry/20110910/1315609950 http://qiita.com/hp0me/items/b619680611fd6667273f

Apple系が発祥のNSPropertyListSerializationクラスでパースできる*1、データ永続化などのために使われるファイル形式。 プロパティリストと呼ぶみたいです。

代表的なものはアプリの設定を保存している Info.plist だが、それ以外にも利用可能なようです。 ファイル形式としてはXMLの一種だと思います。*2

*1:NSArray や NSDictionary クラスでもまぁできる

*2:そういえば、AndoridのSharedPreferencesの実装もXMLだったはず http://qiita.com/ochim/items/dc4d77d478e87c1449ad

ideviceinstallerで「Could not connect to lockdownd. Exiting.」と出てアプリのインストールに失敗する

$ ideviceinstaller -u b93fd1bed1bbdf952070fa4160a34510efbe71ee -i /Users/woshidan/to/app/dir/iOSApp/build/sym/Release-iphoneos/iOSApp.app
Could not connect to lockdownd. Exiting.

github.com

Mac OS X El Captain以降のバージョンだと、iOSアプリのインストールに利用している ideviceinstaller が依存している libimobiledevice のバージョンが古い場合、iPhoneにアプリをインストールする際に操作する必要のある /var/db/lockdown の編集権限がない場合があります。

この場合は、libmobiledeviceから新しく入れ直してした後、古い /var/db/lockdownディレクトリ以下を削除してやり直すと自分の場合は解決しました。

brew uninstall ideviceinstaller -g
brew uninstall libimobiledevice -g
brew install --HEAD libimobiledevice -g // libimobiledeviceの新しいバージョンを入れ直す
brew install ideviceinstaller -g
sudo rm -rf /var/db/lockdown/*

NoSQLの種類とNoSQLのアプリケーションの例について

NoSQLは、一人のユーザーが書き込んでから他の人が参照するデータに反映される間には少し時差があるけどいいだろうというゆるい整合性(結果整合性)で動いているんだ、といった話をこちらあたりで読んでなんか面白かったので少しだけメモします。

RDBMSとNoSQL

RDBMSは即時での一貫性を求められる基幹システムや在庫管理システムなどをはじめとしてWebアプリケーションのデータベースとして広く採用されています。RDBMSはデータの整合性を保証する代わりにトランザクションのコミット前に通信や待ちが発生するため、アプリケーションがたくさんのリクエストに応える必要が生じるにつれ、パフォーマンス的に厳しいものが出てきました。

NoSQLはこのRDBMSの状況の対抗策として登場したものとなります。 ざっくりいうと、ネットワーク上でデータを分散して管理するシステムにおいて、RDBMSの整合性を保証する代わりに遅い、という部分の逆をいく、みたいな形で作られたものであって、じゃあ逆ってなんなのだ、という話になります。

CAP定理

ネットワーク上の分散システムの性質に関して「CAP定理」*1があります。CAPのそれぞれの文字は

  • Cが Consistency(整合性) = 複数のシステムのノード間で読み書き結果が矛盾しない
  • Aが Availability(可用性) = (特に更新)停止しない
  • Pが Partition Tolerance(ネットワーク分割耐性) = ネットワークの一部に障害が起きても動作可能(SPOF(単一故障点)を持たない)

から来ています。

CAP定理は、ネットワーク上の分散システムは、この三つのうち二つしか満たすことができないというものです。後に、提唱者のBrewer氏自身により、CAP定理の過度な単純化は問題であるとされ、割合やバランスの問題であるという具合に訂正されています *2

しかし、ここでは単純のため、RDBMSを含むデータベースがどの性質を満たすのか、どういったアプリケーションがあるのかを考えてみます。

C, A, P アプリケーションの例 データベースの種類
C(整合性), A(可用性) 銀行口座など,データの矛盾が許されないリアルタイム処理 RDBMS, Vertica(Column-Oriented)
C(整合性), P(ネットワーク分割耐性) 検索エンジンのインデックス処理など,データの矛盾が許されない非リアルタイム処理 MongoDB(Document-Oriented), memcached(K-V), redis(K-V)
A(可用性), P(ネットワーク分割耐性) ユーザーに近く、ダウンタイムがないビジネスで利用する。ショッピングカートやSony PlayStationネットワークなど Cassandra(Column-Oriented)

CA以外、正直、データベース=RDBMS脳の自分にとってはわかりにくいですが、たとえば、Google検索エンジンの更新処理やソシャゲのランキング処理がユーザーの私達から見て秒単位でリアルタイムである必要はなさそうです*3

また、APについては、整合性より、書き込めることが重視されていますが、ゲームのネットワークであるSony PlayStationネットワークが銀行のネットワークシステムより整合性を捨てて速さを優先する、と言われたら、そこ速さがなかったらゲームにならないもんなーと納得したりしますが、実際は個々のものについて触れたり触れなかったりしてその折に考えることになるのでしょう。

現場からは以上です。

参考

*1:数学的には定理ではない

*2:http://www.publickey1.jp/blog/13/capcap32.htmlhttps://www.infoq.com/jp/articles/cap-twelve-years-later-how-the-rules-have-changed

*3:ガチ勢じゃ無くてすみません。。

データベースのデータのバックアップの種類について

データベーススペシャリストの問題を見ていて、データの更新範囲や内容によって、差分バックアップと増分バックアップの使い分けを検討する話が面白かったのでメモ。

なお、最初に断っておきますが、リストア周りについて実際業務で担当したことはなく、興味があったので調べたことをまとめているだけなので、何かあったらマサカリください。

差分バックアップと増分バックアップとは

インターネットで検索したら、記事によって定義が揺らいでいてそのまま使って大丈夫か、という感じだったので、

http://www.atmarkit.co.jp/ait/articles/0306/14/news003.html https://www.backstore.jp/blog/2016/08/17/differential_and_increment_backup/ http://qiita.com/Tocyuki/items/f34ca92b8bf6e0014923

あたりを参考にまずこの記事の中でいちおう言葉の定義をしておきます。それで肝心の定義ですが、

  • 毎回、最後にフルバックアップを取った時点からのデータの差分のバックアップを取るものを 差分バックアップ
  • 最初にバックアップを取るときは、最後にフルバックアップを取った時点からのデータの差分となるが、それ以降は前回バックアップを取った時からの差分になるものを 増分バックアップ

とします。図にすると下図のようになります。

差分バックアップと増分バックアップの使い分け

データの更新され方による使い分けの話

取り上げられていたのは、平成28年度の午後Iの問題なのですが、

  • 結構大きなテーブルで、一部だけが頻繁に更新されるテーブルのバックアップを取る場合
    • 更新範囲が重複しがちなことがわかっている場合、差分バックアップにすると増分バックアップより適用する必要のあるバックアップの量が小さくなる
  • 何かの履歴といった増えることはあっても後から更新されることがないテーブルのバックアップを取る場合
    • 差分バックアップにしてしまうとフルバックアップを取った時点から遠くなるにつれ一度にバックアップを取る量が増えてしまうので増分バックアップにする

という趣旨の内容で、いままで二種類あるけどよくわからないな、差分は容量が増えて悪いやつだ、みたいなゆるふわなイメージを持っていた自分には面白かったのでした。

運用に関するもの

www.backstore.jp www.atmarkit.co.jp

差分バックアップと増分バックアップの定義について調べていたら、そういえば、復旧作業に関する話も出てきていたのでこちらもメモ。

さて、問題に取り上げられていたような巨大な業務用システムのデータベースなどだったら、バックアップのデータをバックアップ用のサーバに転送する時間もバカにならないので上記のようなことを計算してみて考える必要がありますが、実際、ノートPC上のファイルの中身程度だったら毎回フルバックアップで十分ということもあります。

増分バックアップは復元時の各バックアップファイルを適用していく作業が煩雑だったり、途中のバックアップファイルが欠落した場合戻せなくなってしまったりするため、手動で管理する必要がある場合は大変そうです。

差分バックアップはそれぞれのタイミングでのバックアップのデータサイズが前節であげた場合以外は大きくなりがちで、バックアップを取りたいタイミングが増えるにつれて容量を圧迫しがちですが、更新作業に必要となるのは、フルバックアップ + 差分バックアップのファイルのみであり、手順もわかりやすく復旧処理が簡単だそうです。

実際のコマンドについて調べて書こうかと思ったけど、火傷しそうだったのでやめます。

emulator: ERROR: This AVD's configuration is missing a kernel file!

エミュレータネタ連発。上記エラーが発生した時に確認することを順にメモ。

エラーメッセージ全体

Cannot launch AVD in emulator.
Output:
emulator: ERROR: This AVD's configuration is missing a kernel file! Please ensure the file "kernal-qemu" is in the same location as your system image.
emulator: ERROR: ANDROID_SDK_ROOT is defined (/Users/woshidan/Library/Android/sdk) but cannot find kernel file in (/Users/woshidan/Library/Android/sdk/system-images/) sub directories

発生したエミュレータAPIバージョンとABIとどこ製か

一部のエミュ(主にARM系)のエミュにはGoogle社製のものとAndroid Open Source Projectによるものがあって、自分の手元で発生したのは

で発生。

kernal-qemuとは

QEMUとは - OSS用語 Weblio辞書

QEMU(仮想マシンエミュレータ)のハード的なところとソフト的なところをつないでくれるソフト。カーネル。 どうも、Androidエミュレータは、QEMUを利用してARM系のエミュをx86などのCPUのPC上で動かしているそうです。

今回のエラーはエミュレータ作成の時に指定したターゲットに対して、このファイルがないと言われています。

実はでもなく、システムイメージが何かよくわかってないので用語や文末がふわふわですが、エミュレータに指定できるターゲットに相当するディレクトリがありまして、そのディレクトリの中に kernal-qemu がないと言われていることになります。

発生した場合に確認すること

  • SDK Manager上で該当システムイメージがインストールされているか
  • システムイメージが入っているディレクトリを開いてみて kernal-qemuがあるか
    • ディレクトリのパスの例
      • Google社製 /Users/woshidan/Library/Android/sdk/add-ons/addon-google_apis-google-16-1/images/armeabi-v7a
      • Android Open Source Project製 /Users/woshidan/Library/Android/sdk/system-images/android-15/google_apis/x86

実際に当該ディレクトリを覗いてみた例

// エラーが出ない
$ ls /Users/woshidan/Library/Android/sdk/system-images/android-15/google_apis/x86
NOTICE.txt      kernel-ranchu       source.properties
build.prop      package.xml     system.img
kernel-qemu     ramdisk.img     userdata.img
// エラーが出る
$ ls /Users/woshidan/Library/Android/sdk/add-ons/addon-google_apis-google-16-1/images/armeabi-v7a
NOTICE.txt  build.prop  ramdisk.img system.img  userdata.img

どうするか

本来はないと言われているkernel-qemuを調達できればいいのですが、いまのところ、Linuxよくわかってないし、方法不明*1。 もしかすると、SDK Managerをアップデートした後、システムイメージをアンインストールして再インストールすると直るかもしれないですが、最新バージョンのシステムイメージが欲しい場合などを除き、Android Open Source Projectの方のディレクトリには kernel-qemu が含まれていたため、未検証です。

また、自分がこの不具合に遭遇したARM系というのはたいていの実機が該当するので、実機で検証するか実機が欲しいと交渉した方が早いかもしれません。

現場からは以上です。

*1:誰かわかったら教えてください