引数の多い関数と表現と設計
引数が多い関数は悪、リファクタリングするべきのような言説を見て引っかかったので、メモ程度に書きとどめておきます。
引数の多い関数は全く悪くない
世の中には引数の多い関数は見にくいので悪!構造体にするなどして減らすべき!と言う意見がありますが、本質的ではありません。例えば、日時を表すクラスを考えるとします。コンストラクタの引数には、(西暦、月、日、時、分、秒)を指定できるとしましょう。
日時(西暦、月、日、時、分、秒)
果たして、これらの引数は減らすことができるでしょうか?もちろん、秒、分をオプショナルなものとして、省略を可能にすることはできると思いますが、もし、秒まで指定したいとするならば、このコンストラクタの引数を減らすことはできないでしょう。それは、このクラスが本来的に6つの変数が必要な自由度を持っていることに起因します。なので、このクラスのコンストラクタの引数は減らすべきではありません。
引数を構造体にする、あるいは Builder パターンを使う
とはいえ、見かけ上の引数を減らすことはできます。引数を構造体でまとめることもできますが、一般化すれば Builder パターンを使うことになるでしょう。Builder パターンでは、あるクラスAを作成するクラス、ABuilderを定義し、各引数やプロパティについて SetB(b) のようなメソッドを用意し、オブジェクトの生成を肩代わりします。しかし、これは1行に並んでいた引数を縦並びに変えただけで、本質的な解決にはなっていません。クラスそのものの複雑さは変わりませんし、作り方によっては引数の設定漏れも増えてしまいます(引数の並びの間違いはコンパイラが指摘してくれるのに!)。Builder パターンはオプショナルなパラメータが多い場合や、可変長の引数を手続き的に扱いたいときに用いるべきです。
引数を分かりやすくできるケース
しかし、引数を分かりやすくできるケースというのは存在します。例えば、将棋盤を作成するクラスを考えるとします。将棋盤は9×9の81マスですから、もし、駒を引数に将棋盤を表現するとしたら、次のようになるはずです。
将棋盤(駒1、駒2、駒3、……、駒81)
これは冗長に見えますが、実際のところ、将棋盤はそれだけの自由度を持つのですから、間違ってはいません。しかし、これを分かりやすくすることはできます。例えば、駒の種類とその位置をセットにした構造体を作り、それを可変長の引数で受け取るようにすることです。
配置された駒(駒、縦の位置、横の位置) 将棋盤(配置された駒1、配置された駒2、配置された駒3、……)
この形は、入力する情報は若干増えることになりますが、最初のコンストラクタよりは、幾分か人間に理解しやすい形になっているはずです。気取った言い方をすれば、将棋盤は空白が多く、そのスパース性に着目した表現とも言えるでしょう。しかし、このコンストラクタは、重複した位置に駒が置かれる可能性があることを留意するべきです(それでいったら二歩とかも考慮しなくちゃいけませんが)。 このようなトレードオフは、引数の設計に限らず、プログラムに多く見られます。プログラムの複雑性をどう紐解くか、という点において、引数の設計は非常に大切です(そして、それはプログラムの設計の本質でもあります)。このような問題をシンプルすぎる物差しで測るのは、あまり得策とは呼べないでしょう。
Unity の iOS ビルド時に Settings.bundle を組み込む
Unity で iOS アプリを作るとき、iOS の設定に設定画面を追加することができる。 こういうの。
アプリ上で設定画面を作ってもいいが、簡単なテスト用アプリや、広く公開しないアプリなら、こっちで設定しまったほうが、バグも出ないし楽である。
iOS の設定画面を追加するには、Settings.bundle というファイルを Xcode のプロジェクトに組み込む必要がある。これは、Xcode のメニューから「File > New > File」を開き、「Settings.bundle」を選択することで作成できる。
設定した項目は、plist の Identifier を使って、Unity から PlayerPrefs
で引くことができる。
var userId = PlayerPrefs.GetString("userId");
ここで1つ注意なのが、PlayerPrefs
には PlayerPrefs.GetInt
や PlayerPrefs.GetFloat
があるが、なぜか機能せず、数値などを入力させたい場合は、自力でパースする必要があることだ。
int.TryParse(PlayerPrefs.GetString("userId"), out userId);
Settings.bundle は Xcode のメニューからも作成できるが、Unity のビルドプロセスに組み込むこともできる。
これは事前に Settings.bundle を用意しておいて、OnPostprocessBuild
で呼び出すことで組み込むことができる。
public class XcodeProjectUpdater { [PostProcessBuild] static void OnPostprocessBuild(BuildTarget buildTarget, string path) { if (buildTarget == BuildTarget.iOS) { AddSettingsBundle(buildTarget, path); } } static void AddSettingsBundle(BuildTarget buildTarget, string path) { // PBXプロジェクトファイルのフルパス string xcodeProjPath = Path.Combine(path, "Unity-iPhone.xcodeproj/project.pbxproj"); // プロジェクトファイルの読み込み PBXProject proj = new PBXProject(); string file = File.ReadAllText(xcodeProjPath); proj.ReadFromString(file); string targetGuid = proj.TargetGuidByName("Unity-iPhone"); string projectPath = "Settings.bundle"; string copyFrom = Path.Combine(Application.dataPath, "Editor/Settings.bundle"); // コピー元の Settings.bundle のパス string copyTo = Path.Combine(path, projectPath); // コピー先の Settings.bundle のパス FileUtil.DeleteFileOrDirectory(copyTo); FileUtil.CopyFileOrDirectory(copyFrom, copyTo); string fileGuid = proj.AddFile(copyTo, projectPath, PBXSourceTree.Source); proj.AddFileToBuild(targetGuid, fileGuid); // プロジェクトに追加する proj.WriteToFile(xcodeProjPath); } }
Unity の IEnumerator を返すメソッドの override
Unity には StartCoroutine というメソッドがあり、これは IEnumerator を引数にとって、非同期実行(別スレッドではない)ができるすごいやつである。
詳しくは公式サイト
これは一見魔法のように動作するが、その実仕組みはとても単純で、やっていることは、下記コードとほぼ同等である。
void Start() { myEnumerator = GetMyEnumerator(); } void Update() { myEnumerator.MoveNext(); }
Coroutine の実行タイミングが気持ち悪い人間は、Update で自力で回せばいいと思う。
さて、Coroutine は便利な仕組みだが、継承すると、やや厄介な問題が生じる。親が IEnumerator なので、そのまま返すわけにはいかないのだ!
override IEnumerator GetMyEnumerator() { yield return base.GetMyEnumerator(); yield return someValue: }
これは期待通りに動作しない。親の IEnumerator もすべて回すには、StartCoroutine を使う必要がある。
override IEnumerator GetMyEnumerator() { yield return StartCoroutine(base.GetMyEnumerator()); yield return someValue: }
しかし、これは MonoBehaviour を継承してないときに困る。 MonoBehaviour を継承していないときは、最初の Update の例のように自力で回せば良い。
override IEnumerator GetMyEnumerator() { var baseEnumerator = base.GetMyEnumerator(); while (baseEnumerator.MoveNext()) { yield return baseEnumerator.Current; } yield return someValue: }
Macアプリの自動起動
展示とかでアプリの自動起動・終了を設定したいときは、launchd でやります。
ユーザー設定からぽちぽちもできるけど、launchdのほうが一気に設定とかできて便利。
1. 実行スクリプトを用意する
Macアプリを起動するならこんな感じ
startup.command
open /Application/Calendar.app
2. plist ファイルを用意する
スクリプトの実行時間とかを書いたXMLファイル。
生成するサイトとかもあるので適当に作る。
com.umaibow.startup.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.umaibow.startup</string> <key>ProgramArguments</key> <array> <string>sh</string> <string>-c</string> <string>/my/path/to/script/startup.command</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>
3. plist を登録する
plist を ~/Library/LaunchAgents/
にコピーして、コマンドから登録する
launchctl load -w "~/Library/LaunchAgents/com.umaibow.startup.plist"
解除するときは unload
launchctl unload "~/Library/LaunchAgents/com.umaibow.startup.plist"
テンプレを作った
【ポエム】演技が苦手
昔からなのですが、人が何かを演じている姿というのが苦手です。共感性羞恥の亜種と言うのでしょうか、ドラマや映画で、人が大げさな演技をしているのを見るのが、非常に苦手なのです。何か驚いたときに、目を見開いて「わあ!」と声を上げたりだとか、怒り心頭で拳をわなわなと震わせながら、怒鳴り散らしたりだとか、そういうのを見ると、一気に冷めてしまうのです。もともと、自分が感情の発露が少ない人間だということもあり、自分なら絶対にしないような立ち振る舞いを見ると、何か、同じ人間の形をした別の生き物を見たような気持ちになりますし、嬉しくないのに笑ったり、悲しくないのに泣いているという事実に、ある種の恐怖のようなものも覚えます。同じ理由で、大げさなリアクションを取る芸人や、アイドルも苦手です。これらのようなことが、テレビの中だけならいいのですが、たまに現実でもこういった大げさなリアクションをする人がいて、たぶん、それはおそらく、そういったリアクションがテレビから逆輸入されたものだと思うのですが、まあ、とにかくそういう振る舞いに乗っかれればいいのですが、どうしてもスッと冷めてしまって、素っ気ない態度を取ってしまったりして、でも、それはそれでその人なりの愛なのだろうとも思うと、とても心苦しくなったりして……。それでもガッとテンションを上げて、あるいはお酒の力を借りたりして、応えることもできるのですが、どうしても嘘を吐いているような気分になり、あとで後悔をしたり、そういうコミュニケーションを重ねれば重ねるほど、逆に距離が離れていくように感じてしまったりして、結局、どこかでプツンと糸が切れてしまい、どうしようもない自己嫌悪や申し訳なさに襲われることになります。他人に嘘を吐くことは得意なのですが、自分に嘘を吐くことが非常に苦手なのだと思います。だから、自分に対して平気で嘘を吐ける、ように見える、人が苦手という部分もあるのかもしれません。それでも、自分に嘘を吐いていることが透けて見えるような人は、それが逆に愛おしく思えたりするのですが、それすら見えない、テレビに出ているタレントのような振る舞いをする人は、怖くて仕方がないです。