プログラマのつれづれなるままにプログラマのつれづれなるままに音宮志久が思ったことなどをネタにします。プログラムネタ・数学ネタがメインです。Objective-C「Objective-C」カテゴリーアーカイブiOSのバージョンが上がるたびにdeprecatedがコメントを残すというわけで、今回はこんな愚痴ともとれるタイトルをつけさせていただきたいと思います。iOSはバージョンアップが比較的早いOSですので最新の機能が反映されやすい状態になっています。これがプログラマからするとかなりの負担になることもある、ということを今回はちょっと書いていきたいと思います。先に言っておきますがこの場合のdeprecatedとは「推奨されない」という意味を持ち、指定されている機能を使わない様にすることといった意味や今後この機能が廃止されるという警告を含んでいます。iOS7の更新もやばかったがiOS8の更新もやばかったのねiOS6からiOS7に上がったときはUIが大幅に刷新された影響でそれに関してのdeprecatedが大量に出たターンでした。テキストやらボタンやらで独自の処理をやっていたパターンだと見た目でOSの状態に合わせる、となるとかなりの修正量が必要になったと思います。アプリ内で黒を基調としていた状態から白を基調にする様になるパターンに変えるのにバージョン判定により状態を切り替える、というのが頻発することに。iOS7からiOS8です。今回の変更で最大の問題点はUIActionSheetとUIAlertViewが(コンパイラ上では警告されないが)UIAlertControllerとなることでdeprecatedになったことで、それに付随してiOS7までUIActionSheetでできた「UIActionSheetをシートが標準で現れるUIViewと見なしてシート上に別のUIを配置する」という裏技が完全にできなくなったことですか。UIDatePickerをUIActionSheetに乗せて・・・というパターンは多かったらしく、わざわざこれのためのコードを作った人もいるくらいですからね。ちなみにUIActionSheetやUIAlertViewがUIViewを継承しているのに対してUIAlertControllerがUIViewControllerを継承していることからも分かる様にUIAlertControllerで別のUIを配置することはできないようですのであしからず。がんばってそれができる様なViewを作って処理をしましょう。これに関してはどのくらいUIActionSheetを利用しているか?にも依存しますのでどんなコードが良いのかを示すことは簡単にはできません。(float)ver;}というルーチンでも作ってこれを利用すれば問題は無いでしょう。次のバージョンでは何がdeprecatedになるのやら昔からiOSでアプリを作っている人や修正を請け負っている人だと気になるところだと思います。私もこういう記事を書いているくらいですから気になります。二年たったくらいでUIがまたもや大幅刷新される、ということは無いと思いますが、それでもdeprecatedによってアプリが動かなくなる、というのはかなり厳しいですよね。需要があるアプリであれば仕事にはなるのでそのあたりを考えると何ともいえなくなってしまうのが考え物ですか。志久コードの入力補完機能って意外とうるさくないですか?コメントを残す最近の開発環境だとだいたいこの機能ってついていますよね。VisualStudioにしろXcodeにしろEclipseにしろ。IntelliSenceという名前の場合はVisualStudioだけですが、入力補完処理がほかの統合開発環境(IDE)だとどのように呼ぶのか知らないのでとりあえず汎用的に意味を示すような題名にしてみました。使っているVisualStudioのバージョンが古いので最近のものは余り知らないのですが・・・。今は仕事の関係でXcode5を使い始めています。これの入力補完がやたらとうざいと感じています。設定を変えて黙らせれば済むだけなのかもしれませんが、多少は使うので結局はこの機能と仲良くなるしかないんですよね・・・。コンパイル前に変な警告をさせるととてもいらつく警告は警告なのでされないよりはましなのですが・・・。今現在やっているXcode5の処理でいらついている警告が三つありまして、それがswtich-case構文でenumにより宣言されている変数を指定するとdefaultが無い限りすべての処理を記述するように警告されるprintf系の構文でformatが変数の型と合わない、特にintやlong(+unsigned)の差を正しくするように警告されるdefineプリプロセッサで可変引数によるマクロの場合、引数がないと警告されるです。プログラム的には分からなくもない(printf系構文であれば変数の型と合わないとアタックをかけられるかもしれないので)ですが、個人的には行き過ぎのような気がしています。いやなのがこれをコンパイル時の警告として表示するのではなくコード上に表示することなんですよね・・・。Xcodeは確かに前からコード中に表示するようになっていましたが、なんか納得がいかないんですよね。これもありますが、VisualStudioでもあるのが命令文の終了である「;」が抜けた時の警告。単なる書き忘れで行を変えた時に警告が出るのはコンパイル前にチェックできてありがたいのかもしれませんが、なんかコンパイル前にこれが出されると自分がダメ人間のような錯覚を受けるのは私だけなのでしょうか・・・。いらないコードを補完しないでほしいObjective-Cの場合はインスタンスへのメッセージ送信、という考え方の関係上引数の名前呼び出しが言語の仕様上可能になっています。普通にコードを書いている分には対象のインスタンスで呼び出すことができるメッセージを表示してしかも引数としてあり得そうなものまで表示されているのでありがたいような気もするのですが、例えばここで先頭にメッセージ呼び出しの括弧が足りない時はさあ大変。括弧のつじつま合わせをしようとパラメータ部分に勝手に括弧が付け足されるわ、気がついて括弧を削ってもカーソルを移動させたらまた就いてくるわ。ここまで来るとお節介もいいところです。ちなみにちょっとした間違いで呼び出すメッセージを書き直した場合でも前に補完されたパラメータ部が残ったままになってなんかとんでもない状況となったりと。削除するのも一手間なんですが、これって対処法とかあるのでしょうかね。VisualStudioの場合は呼び出すメソッド候補をリストで表示するところまでしかない(はず)なのでマイルドな処理ですよね~。VisualStudioとXcodeのキーアサインの違いに苦しむこれはツッコミのおまけです。個人的に困っているのが行頭に戻る処理と行末に移動する処理です。VisualStudioは行頭移動がHomeキー、行末移動がEndキーなんでこれを使用することが多いです。これがXcodeに持って行くとHomeキーがコードの先頭行への移動、Endキーがコードの終端行への移動となんか困ったことになっています。こちらもキーアサインを何とかすればいいような気もしないでもないですが、行頭にカーソルを持って行きたいだけなのに間違えてコードの先頭行に移動してしまうと元の編集行を探すのが一苦労なんですよね・・・。他にもありますが、この辺は愚痴になるのでこの辺で。この手の補完機能って初心者には親切なのかな?この後でプログラム講座でもまじめに開こうかと思っている私ですが、補完機能があることにより逆に分からなくなることがありそうで怖いです。自動的に表示されるいくつかの警告、例としては行末の「;」を忘れた時の警告はコード内に直接出るようになっていますが、これだと「コンパイルした時に出るエラーの意味をひもといていく」というプログラムを作っていく上で重要な学習の手順が抜けることが問題になると個人的には思っています。それとも逆に「コンパイル前に分かったことが良かったこと」としてとらえるべきなのでしょうかね。これも開発環境の変化による新しい考え方なのでしょうかね。ちなみに本当の初心者の人であれば「まずはサンプルをいろいろと作ってみて動作を見てみる」のをおすすめします。「サンプルを手に入れてビルド」ではありませんよ。自分で打ち込むことに意義がありますからね。コードを書く時に見やすいコードの書き方やコードの流れを打ち込みながら覚えていく、という手順はプログラムをかけるようになる流れの中で必要だと思いますので。志久UILocalNotificationのサウンドファイルの説明に惑わされた・・・コメントを残すこれで立ち止まるようなアプリを組んでいる人はいないとは思いますが、実際に私がはまって、かつそれ系の正確な説明がどこにもないのでここでそれを紹介します。iOS4.0以降はマルチタスクが採用されているので、アプリがバックグラウンド状態になったときにシステムからユーザーへの通知ができるようにUILocalNotificationというインターフェイスを用いてその情報をシステムに登録することができます。Appleの解説ページでも探せばサンプルコードがあります。sound.と書いてあります。問題は、この英文の翻訳で、私は簡単にこのように訳しました。このプロパティはアプリケーションのメインバンドルにあるサウンドリソースを拡張子付きで示されたもの、もしくはデフォルトのシステムサウンドを使うときはUILocalNotificationDefaultSoundNameを与えます。@"sound/notify.caf";と、mainBundleからの相対パスで記述しなければならないというものである、ということらしいです。(らしい、なのは一応実機debugでそういう結果が出たのでこういうことだろう、という意味)つまり、UILocalNotificationのsoundNameは相対パス記述でなければならず、絶対パスの時サウンドは再生されないということ・・・だと思われます。何とも面倒な仕様ですね。自分の日本語訳が間違っている(相対パスを使うの意味が含まれている)のかもしれませんが・・・もう一つ陥りやすいミスがUILocalNotificationで使えるサウンドフォーマットは限定されているということです。読み飛ばしていたので原因解析に時間がかかりました・・・。一つ今現在でもつまずいている部分があるのですが、それは解決したらまたネタにしたいと思います。志久initWithNibNameのエミュレータと実機の差コメントを残すiOSのアプリを実機でデバッグしようとしたときに起こった出来事です。エミュレータ上では自分の思ったとおりに動作しているのになんと実機で実行するとビューの画面そのものが出てこない、という現象にはまりました。検索をかけてもそんな事例を簡単に発見できるわけもなく、いろいろと調べました・・・。犯人はinitWithNibNameの中にいる!というのもばからしいですが、結果がこれでした。Builder経由の画面設計は簡単なアプリを作るなら手軽で内部動作を考えないで作ることができるのですが、このとき、対象となるUIViewContollerは必ずinitWithNibNameにより初期化されなければなりません。bundle:nil];となるのが普通です。ところが、これにちょっとした落とし穴がありまして、それに引っかかってしまったわけです。initWithNibNameの第一引数はxib(nib)の名前なんですがこれは、基本的に「ビューを作成したときに読み込まれるxibのファイル名となる」ということを私は知らなかったわけです。デフォルトの動作としてnilが与えられたとき、対象のクラス名と同じ名前のxib(nib)ファイルがあるものとして初期化を行うという動作があり、これのおかげでエミュレータ上では正しく動作していました。この「正しく動作する」がくせ者で・・・エミュレータ上ではファイル名の大文字小文字とクラス名の大文字小文字が区別されないでinitWithNibNameが動作するが、実機では区別されている私がこれを実装したときのxibのファイル名が「viewmain.xib」とすべて小文字だったわけですね。ところが、インターフェイスの名前は「ViewMain」と単語の先頭が大文字となるように定義していたために実機上では「ViewMain.xib(nib)が存在しないためにロードできない」と判定されたらしいのです。エミュレータ上ではそれがなぜかスルーして動いていたわけでした。その動作くらいそろえてもいいのでは?という疑問が残っています。志久しばらくObjective-Cのプログラムをやっていましたコメントを残すほとんど一ヶ月ぶりの記事ですね~と。新しいタグを増やしましたが、仕事の関係でObjective-Cのプログラムをやっていました。iPhoneあたりにアプリを下ろすためですが・・・。言語としてはObjective-Cはおもしろいですね。基本にC++があるのでその概念との比較、という形で覚えることができて便利です。C++というよりはWindowsのCOMに近い(参照カウンタ、インターフェイスの要求など)ものからObjective-Cを考えるようにするとちょっとわかりやすいかも。Objective-Cばかりでプログラムをやっていると一つ重大なミスを犯しそうな気がする違いが一つ。Objective-Cでは、オブジェクトの解放は基本的には次のように書きます。nil;このとき、_itemがnil(C++的にはNULL)でもエラーではなく、なにもしない、という流れをくむことになります。これが、COMオブジェクト(=C++)での解放はこのように書きます。NULL;}つまり、lpItemがNULLでないことをチェックしないとReleaseの呼び出し時にNULL参照による実行時エラーとなるわけです。なんかObjective-Cに慣れすぎるとこの辺がバグの温床にもなるような気がしてなりません。一つ、面倒なのが参照カウンタの管理です。はじめやっているとかなり流れに苦しむところだと思います。COMでもそうですが。参照カウンタは「オブジェクトを確保して初期化する」と自前管理になり、「直接取得する」とautoreleaseで扱われる、というのが一般的です。initWithFormat:@"%d",256];と書くと、以下のようになります。str1は「直接取得」とみなされれ、この時点ですでにautoreleaseがかかります。放置しておけば基本的に勝手に解放されます。str2は「オブジェクトを確保して初期化する」ので、自前管理となり、放置するとメモリリークを起こします。使用後にreleaseを行うか、autoreleaseを行って自動解放するようにします。・・・わかりづらいったらありゃしない。違いがわかればそれなりに対応ができるのですが、このautoreleaseというのが微妙にくせ者で、本来は最も内側にあるNSAutoreleasePoolが解放される段階で一緒に解放されるらしいのですが、この「最も内側にある」が特にUIKitを使っているとき(WindowsではMFCを使っているような状況)に不定になるらしく、基本的に「ルーチンを抜けるとすぐにreleaseを発行する」くらいでとらえるのが自然かな~という結論が得られたくらいです。メモリの関係でいつ解放されるのか気が気じゃなかったのですが・・・。(作りすぎてメモリ不足、とかがありそうだった)C++の時は自前制御なので、悩まずにAddRefを使ったりできるんですけれどね~。ま、オブジェクトへのメッセージ処理など言語的にはおもしろそうなのでしばらくは仕事にできそうな予感です。志久プログラムネタや思いついたり世間で話題になっている数学ネタを解説したりしています。プログラマとしては今年度(つまり2020年3月)までの復帰となるか、完全復帰となるか、別の仕事に戻るかは運と実力次第。ちなみに教育系のプログラムでもOKです。アクセスカウンタアクセス数:スポンサーリンク。