JavaプログラマがXcodeでiPhoneアプリを作ってみる.5週目

今週は調査段階で解決できなかったトピックスがいろいろあります。


Xcode 6 beta 5にバージョンアップ

2週間単位でbeta版がバージョンアップしていき、その度に何かしらのSwiftの言語仕様が変更されていきます。今回は、コンストラクタでinitの前にrequiredを書いたり、nilチェックを!xと書いていた箇所をx != nilに直す必要がありました。まだOptional型に関するライブラリ周りの微調整が発生しているようです。


Swift

Swifの特徴は、静的な型をもつクラス型のオブジェクト指向言語であると同時に、関数が「第一級市民」とか「Optional型」とか「タプル」とか「パターンマッチング」をもつ関数型言語でもあります。実際使ったことがないので間違っているかもしれませんが、この辺りの特徴はまんまScalaです。Swift関数型言語の部分が使えるようになるとScalaも理解できるようになるのでしょうか?


XUnit

Swiftでプロジェクトを作成すると、メインのプログラムを書くディレクトリと共に、test用のディレクトリも作られます。スケルトンで作らるクラスはXCTestCaseを継承しており、setUp()、tearDown()やtestから始まるとテストメソッド等、JUnit3の頃に似た作りになっています。もちろん最初から作らているクラス以外にも手動で新規クラスを作ることもできて、XCTestCaseを継承したクラスを作ると自動的にテスト実行時の対象に含まれるようになりました。だいたいJUnitと同じとう理解でいいような気がしますが、AllTestsに相当する概念は無いかもしれません。また、なぜかメインディレクトリのクラスを呼び出すことがで来なかったため、具体的なテストが書けませんでした。
Objective-Cの頃は、JUnitと同じく公式のテストクラス以外にも様々な拡張モジュールがあったようで、Swiftでもビヘイビア駆動のQuickとか、テスト用にモックがつくれるOCMockとかが使えそうです。このあたり、もう少し落ち着いた頃に再調査してみるつもりです。

2014/8/11追記:Target MembershipにTestsを追加するとテストからメインプロジェクトのクラスが呼べるようになるようです。


例外処理

Java使いなので自然とtry-catchに該当する機能を探してしまったのですが、どうも例外処理という概念は無いようです。
参考サイト:Swiftのエラーハンドリング
どうにかして、実機でクラッシュした時に情報を取得したいのですがどうすればいいのでしょうか。。


UI周りその1

そろそろデザイナーチームと連携を取りながら作業をしたいのですが、StoryBoardのmergeがネックになっています。互いに関連のないViewを修正してもStoryBoardのファイルが1ファイルなのでコンフリクトが発生します。どこかで、1アプリ1ストーリーボードが推奨というのを見た気がするのですが、StoryBoardを分割してみようと思っています。現在はっきりしているデメリットは、Segueが使えなくなることです。
参考サイト:Storyboardを1画面ごとに分割した話


UI周りその2

デザイナーが作ったPhotoShopのイメージをXcodeのViewに落とす作業を始めたのですが、UITextViewに余白(CSSのpaddingにあたるもの)を設定しようとしてつまりました。結局コードでUIEdgeInsetsを設定して対応したのですが、もっと楽に実現する方法があったら教えてください。


デバッグ

エミュレータのbreak pointがずれることがあるようです。アプリでクラッシュする箇所があったのでブレークポイントで止めて少しずつ進めながら問題の箇所を特定しようとしていたのですが、クラッシュしたところからもう少し先の行のコードに問題があったとうことがありました。また、同じ箇所を実機で動かすと、ちゃんと動作とブレークポイントが一致していました。ここら辺経験値が足りないのでまだ学習途中ですが、問題の特定には実機の方がいいのかもしれません。または、今思うと明示的にcleanしていれば良かったのかも。


ZIPファイルの解凍

参考サイト:iOSでZIPファイルの圧縮/解凍を簡単に実装する方法
アプリ内でZipファイルを解凍したくて、ここを参考にSSZipArchiveを試してみましが、Objective-CでもSwiftでもビルド時にエラーが発生しました。Xcode 6の問題なのか、C言語的な常識を何か理解していないのかわかりません。

2014/8/11追記:SSZipArchiveが、Xcode6+Swiftで使えました。libz.dylibをLink Binary With Librariesに追加する作業が抜けていただけでした。


JavaプログラマがXcodeでiPhoneアプリを作ってみる.4週目

慣れないMacで、Xcode 6 betaとSwiftを使ってiPhoneアプリを作り出して4週間が立ちました。長らく安住の地だったEclipseを離れてiPhoneアプリを作り出した頃は違和感がすごくありましたが、今は騙し騙し動かせるようになってきています。Xcode6とSwiftに特化した日本語の専門書はKindleの軽い内容のものしか出版されていませんが、今年出たばかりのXcode 5 + Objective-C の書籍でも大体同じような内容なので十分通用します。IDEとしてのXcode 6はXcode 5からそんなに変わっていませんし、Objective-Cのライブラリやクラス体系はSwiftでもほぼそのまま変わらず使用できます。

ステータスバー

iOS7になってから、ステータスバーとアプリの画面が重なるように表示されるようになったそうです。ステータスバーとは、画面の一番上に出るネットワーク接続やバッテリーや時間を表示している箇所です。アプリのナビゲーションバーがステータスバーと一体化するのが、Auto Layoutをつかって下に回りんだりできるらしいのですが、時間が無くて調べきれていません。

アニメーション

アプリではある部分でアニメーションする部分を作りたいと考えています。Cocos2DやGameKitを使うと本当のゲームアプリのような動作ができるのでしょうが、そこまでできるリソースも知識もないのでもう少し簡単な方法でやろうと思っています。幸いiOSにはQuartzCoreライブラリがあるので、CABasicAnimationやCAKeyframeAnimationを使えば想定している動きがつけられそうです。

JavaプログラマがXcodeでiPhoneアプリを作ってみる.3週目

今週は、iPhoneのコーディングには直越関係しない、サーバサイドのJava開発環境をWindowsからMacに移動させる作業がメインでした。Windowsでは割と古いJBossを使っているのですが、MacのJava8 JDK上で同じJBossのバイナリを走らせたら、あっさりなんの障害もなく動きました。EclipseWindows版とMac版でバイナリが異なるので、新たにセットアップが必要でしたが、コード保管のショートカットの変更が必要なくらいで、後はWindowsの「いつもの手順」で開発環境ができました。Javaは偉大です。

XCode 6 beta4

  • 早くもXCode 6beta4が公開されたので、早速バージョンアップをしてみる。バージョンアップされる毎にSwiftの言語仕様が微調整されている。

Swift

  • Dictionaryクラス
    • 5000件程度のデータを表示させようとしたが、画面更新が遅い。
    • 最初はUIViewやCALayerのView周りを調整していたが、原因はDictionaryクラスだった。
    • DictionaryをJavaのHashMap感覚で使っていたが、単純なデータの出し入れがとにかく遅い。
    • Twitterでも同様のつぶやきが散見される。
    • この問題は今後のバージョンアップで解消されると思われるが、とりあえずNSDictionaryを使えば解消される。タイプセーフじゃなくなるけど
  • NSJSONSerialization
    • JSON文字列をNSJSONSerialization.JSONObjectWithData()でNSDictionaryに変換した場合、nilデータが紛れ込むことがある。
    • beta3までだと大丈夫だったので、多分バグ。
    • ループの頭にnilチェックを追加してとりあれずしのぐ。

JavaプログラマがXcodeでiPhoneアプリを作ってみる.2週目

Eclipse使いのJavaプロラマが、Xcode+SwiftiPhoneアプリを作ってみるの2週目です。(1週目は、http://d.hatena.ne.jp/grachro/20140713)。アプリ内容はまだ書けません。

Xcode 6 beta3

  • エディタの動作が重くなってきた。一文字打つごとに数分固まる。タイミング的に、beta2からbeta3に変えた頃が怪しい気がするがさだかではない。
  • http://blog.valeur3.com/?p=1515 ここを参考にキャッシュを捨てたら固まらなくなった

iPod touch (第5世代)

  • ios 8 の実機動作確認にはiPod touchを使用。こちらもbeta3に変えて、アプリの起動までの時間が長くなった気がする。
    • 前はシミュレータで動作させるより実機の方が起動が早かったが、今やシミュレータのほうがで早い。(?)
  • 何かの弾みでiOS8 beta3を入れたiPod toucheが真っ暗なまま何をしても動かなくなった。iTunesからOS再インストールで直った
  • なぜかシミュレータで動くコードが、iPod touchだと動かない。
    • シミュレータで動く「ObjCBool(false)」が、iPod touchだと「ObjCBool(0)」こう

Swift

  • Javaの「if (aObject instanceof String) {..}」は、Swiftだと「if aObject is String {..}」

Core Data

シリアライズ

  • プリミティブなフィールドだと自動的にシリアライズさるるJavaと違い、Xcodeだとフィールドを一つ一つコード上で設定する必要がある。
  • NSKeyedArchiver.archiveRootObject(オブジェクト, ファイルパス)とNSKeyedUnarchiver.unarchiveObjectWithFile(ファイルパス) as? クラスで直接ファイルに保存・読み込みできるので、永続化は楽。
  • テーブル1レコード毎に1ファイルをシリアライズ保存だと相応の処理時間がかかったので、Dictionaryにまとめて1度に保存すると改善した。
    • ちゃんと計測していないが、ファイル操作周りで時間がかかるのだと思う
  • Core Dataを使用していた時より、構造の修正が簡単になり、DAOクラスの見通しもよくなった。
    • トレードオフとしてwhereやorder byを自分で実装しないといけない。

Dictionaryのシリアライズ

  • SwiftでNSDictionaryクラスをシリアライズしようとすると、countが無いとかでエラーとなる。overrideが間違っている?
  • NSが付いていないDictionaryクラスを素直に使えば簡単にシリアライズできた。しかもこちらだとタイプセーフ。
  • Dicionaryのタイプを指定したサブクラスを作りたかったが、文法的にどうすればいいのかわからなかかった。一旦aliasで逃げたがこれだとサブクラスにメソッドが追加できない。
    • Javaの「class Foo extends HashMap {...}」がしたくて
    • Swiftで「typealias Foo = Dictionary」こうしてみた
  • "Swiftで辞書型のストアド・プロパティへのアクセスは遅い?"http://qiita.com/takabosoft/items/b2dd95d6c1cbe651fba4 ・・・このサイトと同じ現象に遭遇。
    • 解決方法もリンク先にある通り、ローカル変数で処理して最後にプロパティ代入で逃げれた。

サーバとのデータ同期

  • サーバtoスマホでのデータ同期で、サーバtoサーバのデータ同期と違う点
    • 粒度は小さくする
    • 失敗する可能性が高い、途中からでもリカバリできるように
    • いつ処理されるかわからない
    • 接続される端末数が不定

その他

  • サーバサイドはJava、クライアントサイドはSwiftでコード書いていると、10年もだいたい毎日書いているJavaの文法を間違うことがある。

JavaプログラマがXcodeでiPhoneアプリを作ってみる.1週目

普段はJava+Eclipseでプログラムをしているのですが、いろいろあってXcode 6 beta + Swiftを初めることになりました。学んだことを書いてみます。Xcode 5もObjective-Cもほぼ触ったことがありません。周りに経験者もいないので先生はGoogleです。間違っている箇所は教えてください。

Xcode

  • ファイルは自動保存
  • gitがディフォルトで使える

Swift

  • 全角文字があると自動保管が効かない(Xcode 6 beta 2の時点)。ファイルを作成すると上のコメントの「2014年」年は消す
  • 基本Objective-Cとライブラリは同じっぽい。Objective-Cとの文法の対応が分かれば、Objective-CのサンプルコードをSwiftに置き換えることが可能。パラメータが省略されていることがあるので、完全に機械的にはできなさそう。
  • JavaのObjectに相当するクラスは、NSObject
  • JavaのMapに相当するクラスは、NSDictionary
  • JavaのArrayに相当するクラスは、NSArray
  • JavaのNullに相当するのは、nil(NSNullは、Nullオブジェクトに相当?)
  • ヌルポをコンパイラーレベルでチェックする仕組みがある。var foo:String?こんな感じで?を使用するとヌルポチェックをしてくれるようになる

View

  • 画面遷移やレイヤ雨とはStoryBoardで設定するとviewがロジックと分離できる
  • XCode 6 betaだとプロジェクト作成時にiPhoneを選んでも画像サイズが大きい。理由は未調査。
  • 後から新しいStoryBoardをiPhone様に作ると、ちょうどいいサイズのViewになる。
  • Auto Layoutを使用すると複数の画面サイズに対応できる

ネットワーク

  • Web Viewでブラウザをアプリのパーツに使える(UIWebView)
  • 手軽にHTTP通信をするなら(var err:NSError? = nil;let data:NSData = NSData(contentsOfURL:url, options:nil, error:&err))
  • 非同期でHTTP通信ができる(NSURL,NSURLConnection,NSURLRequest)
  • 自力でFTP通信もできる(詳細未調査)

永続化

  • アプリ内のデータ保存には、key-value方式とRDB方式が選べる
  • RDB方式は、Core Dataライブラリを使う。Core Dataは、SQLiteを使ったORマッパー。
  • SQLiteを直につかう方法もある。
  • 保存領域には、アプリ専用とか共有領域がある
  • 参考になるサイト・・・http://d.hatena.ne.jp/glass-_-onion/20110904/1315142404

WikipediaのバックアップXMLをMySQLに入れてみる

前回まで

日本版Wikipediaで配布されているXMLを取得して、自宅PCのmediawikiに全記事を入れようとした。
配布されているphp版プログラムだと遅すぎ、Java版だと早いが途中で落ちてソースも見つけられなかったのであきらめた。

ネタ元サイト:http://dumps.wikimedia.org/jawiki

XMLの取得方法

wget http://dumps.wikimedia.org/jawiki/20140503/jawiki-20140503-pages-meta-current.xml.bz2

解凍すると10.3G

XMLを解析してみる

公式プログラムでXMLMySQLのテーブル構造に変換したかったのですが、うまくいかなったので自力で解析してみることにしました。(マニュアルが探せばあると思いますが)

XMLの内容


  
    Wikipedia
    http://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8
    MediaWiki 1.24wmf2
    first-letter
    
      メディア
      特別
      
      ノート
      利用者
      利用者‐会話
      Wikipedia
      Wikipedia‐ノート
      ファイル
      ファイル‐ノート
      MediaWiki
      MediaWiki‐ノート
      Template
      Template‐ノート
      Help
      Help‐ノート
      Category
      Category‐ノート
      Portal
      Portal‐ノート
      プロジェクト
      プロジェクト‐ノート
      モジュール
      モジュール‐ノート
    
  
  
    <a class="keyword" href="http://d.hatena.ne.jp/keyword/Wikipedia">Wikipedia</a>:アップロードログ 2004年4月
    4
    1
    sysop
    
      2168855
      299151
      2004-04-30T14:46:00Z
      
##アカウント情報っぽいので2行略##
      
      
      "LocationMacedonia.png"をアップロードしました。: マケドニアの位置 - 英語版より
      <ul><li>14:46 2004年4月30日 [[利用者:
##アップロード履歴らしきものが500行ほど続く##

      0atpn2yli6qvrd8xzq2nnu6zp0ayovq
      wikitext
      text/x-wiki
    
  
  
    <a class="keyword" href="http://d.hatena.ne.jp/keyword/Wikipedia">Wikipedia</a>:削除記録/過去ログ 2002年12月
    4
    2
    sysop
    
      2168856
      2002-12-06T09:23:16Z
      
##アカウント情報っぽいので2行略##
      
      deleted "Linux": goatse.cx
      Below is a list of the most recent deletions.
All times shown are server (U.S. Pacific) time.
<ul><li>09:23 2002年12月6日 User:Brion VIBBER|Brion VIBBER deleted "Linux" <em>(goatse.cx)</em></li>

</ul>
      gbhvqlwj7ga4v9ghhy0n88iqmlo19vz
      wikitext
      text/x-wiki
    
  
##15000000行くらい略##
Category:存命人物
{{Academic-bio-stub}}
      s4yonjfr6lbm9uua8w99u3np66ekzge
      wikitext
      text/x-wiki
    
  


手始めに「記事タイトル」「カテゴリ」「記事とカテゴリの関係」が欲しいので、データの格納先を探してみます。
ぱっと見こんな形式でしょうか。

mediawik
  siteinfo
    namespaces・・・0:記事、14:カテゴリ
  page
    title・・・記事
    ns・・・namespacesに対応
    id・・・後で必要かもしれないので一応押さえておく
    text・・・記事本文。含まれるカテゴリは[[Category:XXX]]の形式で本文の中に記述されている。

MySQLにInsert

使い捨てですが、実際にMySQLに投入するプログラムを書きました。
投入したデータを眺めたかったのですが、データ投入で時間がかかって週末が終わってしまったので続きはまた後日です。

https://github.com/grachro/jaWikipediaTinyParser

UbuntuでMediaWikiをインストールしてWikipedaの記事を取り込んでみる

0.最初に

Wikipediaの下記ページを元に作業を進めていきます。

Wikipedia:データベースダウンロード

1.Apache,MySQL,PHPをインストール

sudo apt-get install apache2
sudo apt-get install mysql-server
sudo apt-get install php5
sudo apt-get install libapache2-mod-auth-mysql
sudo apt-get install php5-mysql
sudo /etc/init.d/apache2 restart

MediaWikiMySQL以外のDBにも対応している

2.MediaWikiをダウンロードして配置

wget http://releases.wikimedia.org/mediawiki/1.22/mediawiki-1.22.6.tar.gz
tar zxvf mediawiki-1.22.6.tar.gz
sudo mv mediawiki-1.22.6 /var/www/html/mediawiki

3.MediaWikiの初期設定

  1. ブラウザからhttp://localhost/mediawiki/へアクセス。
  2. 画面の説明に沿って設定値を入力。
  3. ブラウザからダウンローできるLocalSettings.phpを/var/www/html/mediawikiへ配置。

4.Wikipediaのデータをダウンロード

http://dumps.wikimedia.org/jawikiにある最新の日付のxmlを取得

wget http://dumps.wikimedia.org/jawiki/20140503/jawiki-20140503-pages-meta-current.xml.bz2
mv jawiki-20140503-pages-meta-current.xml.bz2 /var/www/html/mediawiki

5.WikipediaのデータをPHPMediaWikiに投入

cd /var/www/html/mediawiki
bunzip2 -c jawiki-20140503-pages-meta-current.xml.bz2 | php maintenance/importDump.php

xmlは2.2Gあります。Wikipedaのトップページによると今時点で90万件を突破とあるのでおそらくxmlの中に全データが入っていると思われます。上記のPHPのプログラムで投入すると非常に時間がかかり、手元の環境だと3日ぐらいかかりそうです。

6.WikipediaのデータをJavaMediaWikiに投入

PHPだと時間がかかりすぎます。上記ダウンロードの説明ページにはMWDumperというJavaの投入プログラムも紹介されているのでそちらを試してみます。

wget http://csomalin.csoma.elte.hu/~tgergo/wiki/mwdumper.jar

そのままだとMySQLでエラーになるので設定を変更。

ERROR 1153 (08S01) at line 35: Got a packet bigger than 'max_allowed_packet' bytes
vi /etc/my.cnf
max_allowed_packet=128M
sudo service mysqld restart

これを使って投入すると数時間で終わるペースで投入されますが、、途中でエラーになります。

nohup java -jar mwdumper.jar --format=sql:1.5 jawiki-20140503-pages-meta-current.xml.bz2 2> current4.xml.log | mysql -u root my_wiki &
94,000 pages (1,334.412/sec), 94,000 revs (1,334.412/sec)
Exception in thread "main" java.lang.IllegalArgumentException: Invalid contributor
    at org.mediawiki.importer.XmlDumpReader.closeContributor(Unknown Source)
    at org.mediawiki.importer.XmlDumpReader.endElement(Unknown Source)
    at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
    at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentConten
以下略

ソースが見たいのですが、見つからないので今日はここまで。