Wacom Bamboo Stylus fineline を買ってみた
Wacom の iPad 用スタイラスペン Bamboo Stylus fineline を買ってみた。
ペン先の芯が細いのが気に入って購入。さすがに紙に描くようにはいかないけど、思ったより描き味が良くて満足。とはいえ、今のところ対応アプリが Wacom の Bamboo Paper くらいしかないのが残念なところ。対応予定アプリも発表されているけど、メモ用アプリばかり。お絵描きに使いたいんだけどなあ。これは同時に発表されて 10/3 に発売予定の Intuos Creative Styles 2 に期待するしかないか。
とはいえ、結構気に入ってて、iPad mini でちょっとしたお絵描きをするのがたのしくなってるンだけどね。
ワコム Bamboo Stylus fineline iPad用筆圧ペン グレー CS600CK
- 出版社/メーカー: ワコム
- 発売日: 2014/09/12
- メディア: Personal Computers
- この商品を含むブログ (3件) を見る
Swiftでヘッダドキュメント
メソッドや関数のヘッダコメントに、その説明を書くのは JavaDoc 以前からよく行われていたドキュメンテーションの方法ですが、Swift では JavaDoc スタイルの記述方法がうまく働かなくなっていました。「@param」や「@return」が認識されないのです。
これ、「@param」ではなく「:param:」、「@return」ではなく「:returns:」だと認識してくれるみたいです。
(参考: http://nshipster.com/swift-documentation/ )
ただし、Description と :param: の行の間には空行を挟む必要があるようです。
また、リストも行頭に「-」または「+」をつければ、簡単にかけるようです。
コメントも「/**」「*/」で囲む方法ではなく、行頭に「///」でもよいようです。
追記:
番号付きリストや、定義リスト、ブロック引用も整形してくれるようです。
番号付きリストは、数字1文字とピリオドを行頭につければ 1 から始める必要はないようです。また、「#.」と書くこともできます。
定義リストは術語の次に空行を挟まずに定義を字下げして書きます。
術語を「:」で挟んだフィールドリストも書けます。定義リストに似ていますが、術語と同じ行から定義段落を始めることができます。
ブロック引用は、段落を字下げして書きます。字下げを深くしていくことでネストさせることができます。
Swift で Singleton Pattern
AppleのSwiftで Singleton Pattern を実装する方法について調べてみました。あちこちで言及されているみたいなので、今更感が強いですが。だから実装方法だけではなんなので、スレッドセーフなことを検証する XCTest も最後に書いてみました。
作ったコードは GitHub においておきます。Xcode 6 Beta4 で確認しています。
→ https://github.com/tsntsumi/SingletonPatternInSwift
(git@github.com:tsntsumi/SingletonPatternInSwift.git)
遅延初期化してスレッドセーフな実装方法には 3 つあります。
- グローバル定数を使用する方法
- ネストした構造体を使用する方法
- dispatch_once を使用する方法
グローバル定数を使用する方法
グローバル定数を使用する方法が最もシンプルですが、あまりグローバルスコープは汚したくないなと思います。Xcode 6 Beta4 からはアクセスコントロールがサポートされたので、private をつければよいとはいえ、それでも同じファイル内でアクセスできてしまうところが難点です。
グローバル定数を使用するのは、Swift ではクラス定数がまだサポートされていないためです。この方法では遅延初期化とスレッドセーフをサポートします。
private let globalConstantSharedInstance = GlobalConstantSingleton() public final class GlobalConstantSingleton { public class var sharedInstance: GlobalConstantSingleton { return globalConstantSharedInstance } private init() { NSLog("init GlobalConstantSingleton") sleep(3) // 初期化に時間をかけることで、スレッドセーフかどうかを検証できるようにする。 } }
ネストした構造体を使用する方法
ネストした構造体というのは、クラスの中で構造体を宣言する方法です。クラスと違って構造体はフィールドに static constant を定義できますので、ネストすることでその static constant をクラス定数として使用することができます。
この方法でも遅延初期化とスレッドセーフをサポートします。
public final class NestedStructSingleton { public class var sharedInstance: NestedStructSingleton { struct Static { static let instance: NestedStructSingleton = NestedStructSingleton() } return Static.instance } private init() { NSLog("init NestedStructSingleton") sleep(3) // 初期化に時間をかけることで、スレッドセーフかどうかを検証できるようにする。 } }
dispatch_once を使用する方法
dispatch_once を使用する方法は、従来 Objective-C で使われてきた方法です。ネストした構造体と同様の方法を使いますが、コードが冗長になってしまうようです。
この方法でももちろん遅延初期化とスレッドセーフをサポートします。
public final class DispatchOnceSingleton { public class var sharedInstance: DispatchOnceSingleton { struct Static { static var instance: DispatchOnceSingleton? static var onceToken: dispatch_once_t = 0 } dispatch_once(&Static.onceToken){ Static.instance = DispatchOnceSingleton() } return Static.instance! } private init() { NSLog("init DispatchOnceSingleton") sleep(3) // 初期化に時間をかけることで、スレッドセーフかどうかを検証できるようにする。 } }
スレッドセーフでない方法
最後に対照的な実装方法として、ネストした構造体を使用しますが定数を使用しない方法です。
遅延初期化をサポートしていますが、スレッドセーフではない方法でインスタンスを生成しているため、タイミングによっては複数のインスタンスが生成されてしまいます。
public final class ThreadUnsafeSingleton { public class var sharedInstance: ThreadUnsafeSingleton { struct Static { static var instance: ThreadUnsafeSingleton? } if !Static.instance { Static.instance = ThreadUnsafeSingleton() } return Static.instance! } private init() { NSLog("init ThreadUnsafeSingleton") sleep(3) // 初期化に時間をかけることで、スレッドセーフかどうかを検証できるようにする。 } }
テストケース
このクラスを、次のようなテストケースで検証してみます。
class ThreadUnsafeSingletonTests: XCTestCase { func testSharedInstance_ThreadUnsafety() { var instance1: ThreadUnsafeSingleton? var instance2: ThreadUnsafeSingleton? let expectation1 = expectationWithDescription("Instance 1") dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { instance1 = ThreadUnsafeSingleton.sharedInstance expectation1.fulfill() } let expectation2 = expectationWithDescription("Instance 2") dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { instance2 = ThreadUnsafeSingleton.sharedInstance expectation2.fulfill() } waitForExpectationsWithTimeout(6.0) { (_) in // 二つのインスタンスが等しくないことをテスト。 XCTAssertTrue(instance1 !== instance2, "") } } }
二つのスレッドからシングルトンインスタンスにアクセスしています。上で紹介したThreadUnsafeSingletonクラスでは、初期化で sleep() しているため時間がかかり、インスタンスが複数生成されてしまいます。
このテストケースでは最後の方で二つのインスタンスが等しくないことをテストしていますが、シングルトンであるにも関わらずテストが成功してしまいます。
iPad用スタンド
iPad mini Retina用にスタンドを買ってみた。リビング用とベッドルーム用に2種類。
Anker Multi-Angle Stand
リビング用にはANKERのアルミ製のMulti-Angleスタンド。角度を調整する背面の足の部分はプラスチック製。
Anker スマホ&タブレット用スタンド 角度調整可能 iPhone XS・iPhone XS Max・iPhone XR・iPad・iPad mini・Nexus 7等(シルバー)
- 出版社/メーカー: Anker
- 発売日: 2013/06/07
- メディア: エレクトロニクス
- この商品を含むブログを見る
iPadをホールドするところにも傷がつかないようにかプラスチックパーツがついている。溝の広さはSmart Caseをつけたままでも充分ホールドできる。足は可動式で、角度を調節できる。試しに角度を浅くしてこのブログの下書きを書いてみたけど、特にぐらつきもせず、ちょうどいい書き心地だった。
Sanwa supply Acrylic Stand
もう一つはサンワサプライのアクリルスタンド。直径16cmの円形で、透明なのがきれい。角度のついている円筒の上面においてもいいし、溝に立ててもいい。
サンワサプライ iPad・タブレット用アクリルスタンド PDA-STN8C
- 出版社/メーカー: サンワサプライ
- メディア: Personal Computers
- この商品を含むブログを見る
16cmは iPad miniの横幅 (約13cm) より広いのでどうかとおもったが、16cmは底面のサイズで、上面の直径はほぼ同じくらいなので、はみ出してみっともないということはない。
溝の広さは、Smart Caseをつけたままで丁度いいくらい。逆にいえばつけないと広すぎるかも。
findFragmentById が必ず null を返す
Androidでプログラミングをすることになったので、「初歩からわかるAndroid最新プログラミング・増補改訂版」の電子書籍をを達人出版会から購入して勉強中。この本、昨年の12月頃に改訂されて出たものだけど、既に情報が古くなってしまっているようす。とはいえ、ネットを検索しても最新の日本語の情報を簡単には見つけられなかったので、致し方ないよね。Eclipseというか、ADTのバージョンは本で解説しているバージョンと合わせないとつまずきやすいかも。自分は ADT の v22.6.2-1085508 をダウンロードしてしまったので、つまずいてしまった。この本がターゲットとしているのは v22.3 らしい。
- 作者: 柴田文彦,川口仁
- 出版社/メーカー: インプレス
- 発売日: 2014/01/16
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
最初につまずいたのは新規にプロジェクトを作成したところ。編集エリアには activity_main.xml ではなくて fragment_main.xml が表示されるんだよね。どうやら新しい ADT では activity_main.xml の他に fragment_main.xml というレイアウト XML ファイルが生成されて、ユーザインタフェースなどはここに配置するようになったらしい。まあここら辺はちょっと読み替えればいいだけなのだけれども。「2-2 カウンターアプリケーションの作成」のところで説明されている自動生成された MainActivity.java が、本の内容とは微妙に違っている。
ただ、ADT の仕組みの方も fragment_main.xml の扱いに迷いがあるのではないかとも思う。fragment_main.xml にボタンを配置して、そのプロパティにイベントを受け取るメソッドの名称を書いたところ、fragment_main.xml に対応するクラスではなくて、activity_main.xml に対応するクラスのメソッドが呼ばれる。なんか直感とは違うんですけど。fragment_main.xml に対応するクラスは、UI 要素を持つだけということか。もっとも、フラグメントは複数のアクティビティで共有できるようなので、クリックイベントがアクティビティの方に飛ぶのもわからないでもない。
それはさておき、この章ではボタンがクリックされた時に、テキストビューの内容を変更するようなプログラムを作っている。ということは、fragment_main に対応するためには、そのクラスからテキストビューのオブジェクトを取り出さなければならない。それにはまず findFragmentById() でフラグメントを取り出し、getView() で取り出したルートビューから findViewById() でテキストビューを探し出せばよいということになる。
ところが、なぜか findFragmentById(R.layout.fragment_main) がどうやっても null しか返さない。
よくよく調べると、xml ファイルのどこにも fragment_main の id を定義している所がないのである。
そこで、FragmentManager#add() しているところで、タグを定義するようにして、 findFragmentByTag() で検索するようにしてみた。findFragmentByTag() するところも onCreate() ではうまくいかず、onStart() で呼び出すようにしたところうまくいった。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment(), "fragment_main") .commit(); } counter = 0; } @Override protected void onStart() { super.onStart(); if (counterTextView == null) { counterTextView = (TextView)getFragmentManager() .findFragmentByTag("fragment_main") .getView() .findViewById(R.id.counterTextView); counterTextView.setText(String.format("%d", counter)); } }
しかし、xml でフラグメントの id を定義する方法はないものか。ためしに、activity_main.xml のプレビュー画面に Pallete の Layouts/Fragment をドロップしてみたら、MainActivity.java に自動生成された PlaceholderFragment クラスを選択できた。このプロパティを @id/fragment_main に変更して、以下のコードで動作するもよう。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { // getFragmentManager().beginTransaction() // .add(R.id.container, new PlaceholderFragment()) // .commit(); counter = 0; counterTextView = (TextView)getFragmentManager() .findFragmentById(R.id.fragment_main) .getView() .findViewById(R.id.counterTextView); counterTextView.setText(String.format("%d", counter)); } } // @Override // protected void onStart() { ... }
ちなみに、コードを書けば fragment_main.xml に対応するクラスの方でクリックイベントを受け取るようにすることも出来るようだ。