UITableView reloadData の罠

iOS プログラミングで、UITableViewのセルを頻繁に更新したいときに、reloadDataを使うと罠にはまる。
というのも、古いセルに割り当てられたメモリが解放されず、どんどんメモリ使用量がたまっていく。
これはUIView関係のautoreleaseのタイミングのせいで、仕方ない。

Pasted Graphic


UITableView reloadData many times cause memory leak and slow down application
http://stackoverflow.com/questions/4029603/uitableview-reloaddata-many-times-cause-memory-leak-and-slow-down-application

この現象。
ここでの答えは、 reloadRowsAtIndexPaths:withRowAnimation: を使え、ということだったが、確かにメモリ量はふえないが、例えばセンサデータのような高速に切り替わるデータを扱うときは、更新してる様子は見れたもんじゃない。

正しいやり方は、reloadDataを使わず、セルの中の一部だけ(この場合はセンサデータを表示するUILabelだけ)更新してやる。
ここが参考になる。


//for cell updating
- (
void)updateCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// セルの中身をアップデートの例。この場合は4のTagでとってこれるUILabelの値を変更できる
((
UILabel*)[cell viewWithTag:4]).text =[[dataArray objectAtIndex:indexPath.row] value];
}

- (
void)updateVisibleCells {
for (UITableViewCell *cell in [tableView visibleCells]){
[
self updateCell:cell atIndexPath:[tableView indexPathForCell:cell]];
}
}


こういうメソッドを用意してやって、updateVisibleCellsを呼べば、見えてる場所のセルの中身だけ更新されるし、
きちんと一つだけの更新したい場合は、updateCellだけ呼べばOK。

ニコニコ生放送のコメントをJavaで取得

昔ニコニコ生放送のコメントを取得してごにょごにょするプログラムをJavaで書いてた時は、NicoAPIWrapperというのを使わせてもらってたのですが、久しぶりに昔書いたプログラムを使おうと思っても、ニコニコ生放送のログイン仕様などが変わったせいか、動きませんでした。

なんかないかなぁ、と探してみたのですがそのまま動くものがありませんでした。残念。
ブラウザのコンソールでニコ生側とブラウザとのやりとりを眺めてみると、どうやらログイン時のパラメータの渡し方などが違うようです。
これだけだったら簡単に直せそうなので、やってみましょう。

元のコードとして、今回は、
ニコ★リブというプロジェクトの中の、Nico-Lib-Java-Hal というのを使ってみることにしました。(Nico-Lib-Java-Talisker@ZQNというのでも、改良すればいけました)

ここからNico-Lib-Java-Halをダウンロード:
http://sourceforge.jp/projects/nicolib/scm/svn/tree/head/Java/

変更するのは、nicolib.api.Common.java だけで良さそうです。
loginメソッドの中のプログラムを、下記のように変えます。



// オリジナル
//String param = String.format("mail=%s&password=%s&next_url=", mail,password);

// takuroが直した
String
param = String.format("mail_tel=%s&password=%s&next_url=", mail,password);

/**
* オリジナル
* HttpURLConnection http = null;
* try {
*
* http = Http.postConnection(LOGINPAGE_URL, param, null); String
* cookies = http.getHeaderField("Set-Cookie"); String userSession =
* NicoText.getUserSession(cookies); if(userSession != null){
* Http.setUserSession(userSession); return true; }
**/

// ここからtakuroがなおした
HttpsURLConnection
http = null;
try {

http = (HttpsURLConnection) Http.postConnection(LOGINPAGE_URL,
param, null);

String
userSession = "";

Map headers = http.getHeaderFields();
Iterator it = headers.keySet().iterator();
while (it.hasNext()) {
String
key = (String) it.next();
System.
out.println(key + ":" + headers.get(key));
if (key != null && key.equals("Set-Cookie")) {
userSession = headers.get(key).toString();
}
}
userSession = NicoText.getUserSession(userSession);
System.
out.println("ユーザセッションをゲットなう" + userSession);

// ここまでtakuroがなおした。あとはそのまま・・



たぶんこれで動くと思います。(私の環境では動きました)



IPSJ-Oneの追記(その1)

IPSJ-One、分野横断的に最新の研究トピックが知れて、大変勉強になりました。アツい人たちといると、とっても心地よいです。運営の皆様、登壇者の皆様、ありがとうございました。
今回5分のプレゼンでしたが、そのスライド作成の過程で研究を振り返ってみると、色々当時の記憶が蘇ってきてたので、追記ということでメモしておきます。

(1)センサ情報と映像をつなげるお話

まずはセンサ情報を今の映像配信サービスでどう流すか、というお話をしました。

もともとの研究のきっかけは、熊本の方から、「熊本と東京をつないだ遠隔ライブをやりたいので、協力してくれないか」というお誘いからでした。昔ニコニコ生放送を使った映像配信支援の
論文を書いてたことがあり、偶然その研究を知って、コンタクトしていただいたようです。もともとは上述した論文で作っていたシステムを使えないか、というお話だったのですが、せっかくやるなら何か新しいことをやりたいのだけど、それを許して頂けるなら、という我儘なお願いを聞いていただき、適宜相談の上お手伝いすることになりました。(新しいものが作れなかった場合は既に作っていたシステムを使う、というセーフティネットは一応用意)

この時点で決まっていたのは、
・一ヶ月後に本番
・出演アーティストは、
GUSTAVE COQUIOT と、Bird By Snow 。どちらも素晴らしいミュージシャンです!
・映像配信はUSTREAMで行う(安定した配信と高品質な音を流したい、という前提がありました)
ということでした。

何をやるか、とりあえずアーティストの方と相談の機会を設けてもらいました。通常のライブと遠隔ライブの、
・アーティスト目線での違い(たとえば観客からのフィードバックが乏しい)
・観客目線での違い(たとえばカメラで切り取られた視点からしか見えない)
などから、雑談まで、色々とお話させていただきました(ちなみにこの場には何故か東大暦本研のS藤さんにも同席してもらっていましたw)。
あとは、隣の研究室のN村先生と休憩中の雑談で、坂本龍一さんの遠隔ピアノライブをお手伝いしてたときの話を伺いました。「当時は遠隔で演奏したピアノのMIDI情報をネットで送信して、リモートのピアノが動く、みたいなことを行ってた」みたいなお話を聞けました。
これらの相談から、

(演奏側ー>観客側)
・アーティストの演奏してる全身のモーションデータをUSTREAMの映像と同期して届けて、
・そのモーションデータを視聴会場で再現し、観客がUSTREAMの映像に加え、自由な視点でアーティストの動きをみれるようにする

(観客側ー>演奏側)
・観客が一番見たがっている視点を抽出し(再現したアーティストの全身モーションに対する観客の注目点の抽出)、アーティスト側に送信
・その情報から、カメラや照明をコントロールして盛り上がりなどをフィードバック

というシステムを作ることにしました。一つチャレンジングなのが、「全身のモーションデータをUSTREAMの映像と同期して届ける」のをどうするか、という問題でした。今回は配信側と視聴側は1:1なのですが、通常は1:多なので、同期問題やスケーラビリティなどを考えると、別ストリームを用いて頑張って同期して届けるよりも、なんらかの形でUSTREAMの映像に付与できた方が今後のためにもよいのでは、ということになりました。

unknown

(当時のメモ)

映像にデータを埋め込む方式はいくつか提案されてますが、調べたところシックリくる方法が我々の調査力だと見当たりませんでした。そこで、「センサデータストリームをそのまま動画のQRコードに変換して映像と合成すればいけるのでは」、というアイデアを考え、プロトタイプを作って色々試験してみたところ、無事30FPS程度で読めることがわかったため、そのアプローチを採用しました。常に30FPSで全てが読めるわけではないのですが、もともとセンサデータ自体欠損もあるし、30枚のうち1、2枚が落ちても、センサデータを対象とする上では問題にならないだろう、と判断しました。

ということで、モーションデータを既存映像配信サービス上で送ることができ、(観客側ー>演奏側)のシステムもつくり、何とか(?)当日のライブを乗り切りました。

unknown
(アーティストの映像配信側システム。カメラ4台+Kinect。カメラ切替やズームインソフトなども手作り。)


Pasted Graphic
(2枚のスクリーン・プロジェクタを使い、USTREAMからの映像と、その映像から抽出したモーションデータから作ったCGをそれぞれ投影)

R0019937
(アーティストの方々と記念撮影)

その後、モーションデータだけではなくて様々なセンサデータを対象にし、
・センサデータフォーマット(今はバージョン3を実装中)
・QRコードのサイズをおさえるためのセンサデータの圧縮
(今はバージョン2を実装中)
などの課題に取り組みながら、少しずつ作ってきました。
データ再生側も、モーションデータの場合はCGだけじゃなくて実際にロボットを使ったりして、姿勢制御って難しいなぁなどと思いながら作ったり。リアルタイム記録 or 配信に関しては、センサデータと映像を同期させるために1/*(FPS) 秒以内にセンサデータのフォーマット化、圧縮、QRコードへの変換、映像と合成、を行う必要がある。つまりハードリアルタイム性が要求され、そのあたりも面白いところです。

そんなこんなで色々作りながらも、最終的には
tetujinさんの多大な努力の結果、Senbayアプリをリリースするに至りました。

なお、私たちの方式は映像の一部を二次元コードのために用いるという、かなり割り切った方式になってます。これにはもとの映像の美しさを損なうなど、利点と欠点があるので、あらゆるケースで正しいアプローチにはなりえないと思います。
映像になんらかのデータを埋め込む方式は、MPEG7(*1) や電子透かし技術(*2, *3)、など色々あるので、その辺りの動向をうまく見ながら、実際のサービスとして使えそうな・動きそうなものを作っていければ、と思います。また、今回のは欠損が許されるセンサデータを対象とする、ということで、ライブラリなどの普及性などからQRコードを活用しましたが、漏れのない信頼性の高いデータ転送を独自の二次元コードで行う、という研究(*4)もありましたので、こちらもご興味のある方はご覧ください。

(*1) Mpeg-7. http://mpeg.chiariglione.org/standards/mpeg-7.
(*2) Potdar, V. M. et. al . A survey of digital image watermarking techniques. In Industrial Informatics, 2005. INDIN. 2005, pp.709–716.
(*3) Tianxing Li et. al. HiLight: Hiding Bits in Pixel Translucency Changes, Mobicom2014, pp. 383-386
(*4) VCode - Pervasive Data Transfer Using Video Barcode


長くなったのでここでひとまずきります・・

Mac OSX でJavaアプリをアプリケーション(.app)化

いつのまにかOSXが提供するJar Bundlerがなくなってたので、YosemiteとかでJavaアプリを.app化する方法。
(1)起動可能なjarファイルの作成、と(2) AppMakerによるapp化 の2ステップで簡単にできます。

(1) 起動可能なjarファイルの作成
Eclipseプロジェクトから、Export -> JavaのRunnable JAR file を選択。
Launch configuration からメインプログラムを選択して、Export destinationを適当に決める。
Library handlingには、Package required libraries into generated JAR が僕の環境だと一番しっくりきました。
これで、必要なライブラリなどもexportするjarファイルに含まれます。

Pasted Graphic

あと、app化するときにアイコンに使いたいicnsファイルをネットから探しておきましょう。

(2) AppMakerによるapp
ここからAppMakerをありがたくダウンロードさせていただく。
http://sourceforge.net/projects/jarappmaker/

あとは、AppMakerを起動して、(1)で作成したjarファイルと、アイコンを指定して、起動に必要なJavaのバージョンを指定して、Startボタンを押せば、できます。

Pasted Graphic 1

簡単!!


OSX YosemiteでQTJavaを動かす

過去のデモがProcessing1.0系でQTJavaで動いてるので、それをそのままYosemiteで動かしたい場合のメモ。

http://www.compadre.org/osp/bulletinboard/TDetails.cfm?FID=57&TID=3331&ViewType=2

ここを参考に、まずQTJava.zip と l
ibQTJNative.jnilib をどこからかゲットしてきて、
/System/Library/Java/Extensions
ここに置く。

そのあと、Tracker をダウンロードしてきて、入れる。

http://www.cabrillo.edu/~dbrown/tracker/installers/Tracker-4.87-osx-installer.zip

あとは動きます。
32bitモードでJavaプログラム起動しないと動かないかも?
実行時のVMオプションに -d32