2010-11-26

Cocoa Bindings の使い方 #2 - Interface Builder 編

前回の記事(→「Cocoa Bindings の使い方」)では、Cocoa Bindings を使うことで、MVC のうち M (モデル) となるコードを書くだけでアプリが作れると書いた(標準部品とその振る舞いだけを使うアプリの場合)。ただし、その設定には Interface Builder に対する慣れが必要だ、とも書いた。

今回は、Interface Builder を使って Cocoa Bindings を設定する手順について書く。ネタ元は公式ドキュメント(Mac OS X Reference Library)の「Interface Builder User Guide」にある「Connections and Bindings」だ。

ヒレガス本の Chapter 8 でも、NSTableView を NSArrayController に結びつける手順が説明されている。サンプルアプリを作る手順をたどるハンズオンの資料としてはわかりやすいが、ツールについての説明が必要最小限にとどめられているため、自分でアプリを作ろうとすると情報が不足していることに気付く。上記のドキュメントはその足りない部分を補完してくれる。

「結びつき(Binding)」を作る

「Connections and Bindings」の説明用に貼られているパネルのスクリーンショットは、(説明に使う)一部だけを開いてあるためダマされてしまうが、このパネルには似たような設定項目を持つセクションがいくつも並んでいる。

たとえば、右のスクリーンショットは、前回の記事で紹介したサンプルアプリの設定をしたときのものだが、複数のセクション(「Availability」とか「Controller Content Parameters」とか)に、右向きの三角が付いた項目がいくつもあることがわかる(「Availability」に「Editable」、「Content Controller Parameter」には「Filter Predicate」や「Selection Indexes」)。この右向き三角を開くとそれぞれに「Content Array」に表示されているのと同様な設定(「Bind to:」、「Controller Key」や「Model KeyPath」など)がある。

それぞれのセクションや項目がどういった「結びつき」を作るためのものなのかを知らないと、うっかり他の項目に「結びつき」を作ってしまうことになりかねない(前回のサンプルアプリでは実際そういう間違いをしてしまった)。これらの項目はオブジェクトのクラスによって変わるため、それぞれの項目がどういう振る舞いのためのものかは個別のクラスのリファレンスを参照するしかないようだ。一方で、それぞれの項目に対する設定のうち共通なものについては、「Connections and Bindings」の Table 7-1 に「Common binding attributes」としてまとめられている。

どの項目であれ、最低限、設定しなければならないのは「Bind to:」と「Model Key Path」の 2 つ。右のスクリーンショットでは、それぞれ Feed Controller、entries となっているものだ(この例では結びつける相手が NSObjectController のため「Controller Key」も指定している)。

「Bind to:」は文字通り、どのオブジェクトに結びつけるかを指定するもので、ドロップダウンリストを開くと Interface Builder のドキュメントウィンドウ(左のスクリーンショット)にあるオブジェクトの一覧が出る。先の例ではこの中の Feed Controller が選ばれている。

前回の記事に書いたとおり、このサンプルアプリでは NSArrayController が制御する配列(NSMutableArray)は別のコントローラ(NSObjectController のインスタンスで Feed Controller という名前にしてある)が制御するモデルオブジェクトが抱えるものだ。この配列に対する結びつきを指定しているのがこのパネルでの設定になる。

一方、Feed Controller 側と(配列を抱える)モデルオブジェクトとの結びつきも Interface Builder で設定している。右のスクリーンショットがその設定となる。ただ、こちらの設定は Cocoa Bindings とは異なり、NSObjectController が直接モデルオブジェクトを持つための設定だ(と思う)。ただ、そのアクセスに KVC が使われている。

「結びつき」のパターン

「Connections and Bindings」では、結びつきのタイプを以下の 3 つのパターンに分類している。

  • Binding Directory to the Value (値に直接結びつける) [Figure 7-6]
  • Binding Through an Intermediate Object (中間オブジェクトを介して結びつける)
  • Binding to a Collection Objects (オブジェクトの集まりに結びつける) [Figure 7-9]

「中間オブジェクト」パターンについては、さらに 2 つに分けている。

  • Binding through another data object (別のデータオブジェクトを介して結びつける) [Figure 7-7]
  • Binding through an object controller (別のコントローラを介して結びつける) [Figure 7-8]

この分類にしたがえば、前回のサンプルアプリは、「別のコントローラを介して結びつける」と「オブジェクトの集まりに結びつける」の複合方式ということになる。

まとめ

前回のサンプルアプリはヒレガス本の手順を真似て、さらに「結びつき」を作るための試行錯誤を繰り返して作った。そうして動くモノができたものの、すっきりしない感じが残った。そのモヤモヤが「Connections and Bindings」を読むことで氷解した。とはいえ、最初にこのドキュメントに取り組んでいたとしても、すんなりと理解はできなかったに違いない。試行錯誤の後だからこその理解だと思う。

馴染みの薄い概念がふくまれていると、ドキュメントを読んでも表面的な理解で終わってしまう。そこが難しいところだよね。

ちなみに、この記事では「バインディング」「バインドする」とカタカナ表記で書くのが嫌で「結びつき」とか「結びつける」と書いてみた。Lisp 界隈で bind の訳語として定着している「束縛」を使わなかったのは、以前からなんというか語感が堅いと感じていたから。

ま、自分では、脳内で「bind」に変換して読んでいるんだから、どっちでも良いんだがね。他の人はどう感じるかな (・ω・)?

参考文献

Cocoa Programming for Mac OS X
Aaron Hillegass
Addison-Wesley Professional ( 2008-05-15 )
ISBN: 9780321503619

関連リンク

関連記事

2010-11-25

Cocoa Bindings の使い方

追記@2010-11-30

Cocoa Bindings の使い方については以下の後続記事も参照のこと。

ブログの記事一覧を表示するようなアプリでは、記事一覧のデータは、配列(のような何か)に蓄えることになるし、画面の表示は表形式(に似た何か)を使うことになるだろう。

Cocoa アプリでこれをシンプルに実現すると、配列 (NSMutableArray) に蓄えられたデータをテーブルビュー (NSTableView) に表示するものになる。MVC アーキテクチャで言うなら、配列がモデル(正確には配列に蓄えられたオブジェクトがモデル)で、テーブルビューが(その名の通り)ビューになる。

NSTableView にデータを表示させる場合、二通りの方法がある。1 つは、NSTableView のデータソースとなるクラスを定義する方法。具体的には、AppController というようなクラスを定義し(MVC の C)、そこで以下の 3 つのメソッドを定義するというもの。

  • - numberOfRowsInTableView:
  • - tableView:objectValueForTableColumn:row:
  • - tableView:setObjectValue:forTableColumn:row:

3 つ目のメソッドは表示のみのアプリなら必要ない。

この方法の欠点は、NSMutableArray の内容を NSTableView における表示と同期させるコードは、どれも良く似ているものになることだ。

良く似たものになるなら、その仕組みを共通化してフレームワークが提供してくれればありがたい。もちろん、そのためにはある種の「抽象化」が必要になり、利用に際しては一定の「作法」に従わなければならない。この「共通化された仕組み」が Cocoa Bindings であり、「抽象化」が KVC (Key-Value Coding)、「作法」が KVO (Key-Value Observing) ということになる。

サンプルアプリ

今回、サンプルとして作ったアプリのスクショがこれ(→)だ。機能的には(意匠的にも)ヒレガス本の Chapter 8 で作るもの(→ 「MVC と Cocoaバインディング」参照)と同等だが、こちらは、コードとして書いたのはモデルとなる 2 つのクラスのみで、ビューは当然として、コントローラも Cocoa フレームワークの提供するものだけで作られている。

モデル

まずはモデルを構成する 2 つのクラスを示す。これら 2 つは、Atom 形式のフィードから生成することを想定したものだ。Feed オブジェクトが Entry オブジェクトの配列を抱えるようになっている。

Entry の定義
//  Entry.h
#import <Cocoa/Cocoa.h>

@interface Entry : NSObject {
    NSString *title;
    NSDate *updated;
}

@property (readwrite, retain) NSString *title;
@property (readwrite, retain) NSDate *updated;

@end
//  Entry.m
#import "Entry.h"

@implementation Entry
- (id)init
{
    [super init];
    title = @"Hi!";
    updated = [[NSDate date] retain];
    return self;
}

- (void)dealloc
{
    [updated release];
    [title release];
    [super dealloc];
}

@synthesize title, updated;

- (void)setTitle:(NSString *)newTitle
{
    if (newTitle == title) return;
    [title release];
    title = [newTitle retain];
    self.updated = [[NSDate date] retain];
}

@end
Feed の定義
//  Feed.h
#import <Cocoa/Cocoa.h>

@interface Feed : NSObject {
    NSString *title;
    NSDate *updated;
    NSMutableArray *entries;
    int count;
}

@property (readwrite, retain) NSString *title;
@property (readwrite, retain) NSDate *updated;
@property (readwrite, retain) NSMutableArray *entries;
@property (readwrite) int count;


@end
//  Feed.m
#import "Feed.h"
#import "Entry.h"

@implementation Feed
- (id)init
{
    [super init];
    title = @"My Feed";
    updated = [[NSDate date] retain];
    entries = [[NSMutableArray alloc] init];
    [entries addObject:[[Entry alloc] init]];
    count = [entries count];
    return self;
}

- (void)dealloc
{
    [entries release];
    [updated release];
    [title release];
    [super dealloc];
}

@synthesize title, updated, entries;

- (void)setEntries:(NSMutableArray *)newArray
{
    if (newArray == entries) return;
    [entries release];
    entries = [newArray retain];
    self.count = [entries count];
}

@synthesize count;
@end
コントローラ

コントローラには NSObjectController と NSArrayController を 1 つずつ使っている。これらのコントローラは Interface Builder から NIB (今は XIB)ファイルの中にインスタンス化し、設定を変更しているだけだ。コードは一切、書いていない。

これらコントローラの設定で肝となるのは、それぞれのコントローラが保持することになるモデルクラスとの対応づけだ。NSObjectController は 上述のFeed クラスのオブジェクトを保持する。NSArrayController は Entry クラスのオブジェクトを生成し(Add ボタンのアクション)、消滅させる(Delete ボタンのアクション)。ただし、Entry オブジェクトたちを保持するのは Feed が抱えた配列だ。このため、NSArrayController は Feed オブジェクトに対して要素となる Entry オブジェクトの追加、編集、削除を指示する必要がある。このとき用いられるのが Cocoa Bindings だ。

NSArrayController は配列を抱えた NSObjectController にバインドされることになる。

ビュー

スクショを見ればわかるように、いくつかのテキストフィールド(いずれも編集不可にしてある)とテーブルビュー(タイトル欄のみ編集可)、および 2 つのボタンから構成されている。いずれも Cocoa フレームワーク標準のビューたちだ。

テキストフィールドおよびテーブルビュー(のセル)は、Cocoa Bindings によって、2 つのコントローラのプロパティを経由してモデルと結びつけられている。このため、モデル(のプロパティ)が変更されれば、KVO の通知により自動的に変更がビューに反映されることになり、ビューによる変更はコントローラを経由してモデルに反映されるようになっている。

まとめ

MVC のうちモデルとなるクラスを書くだけで後は、Interface Builder の操作でアプリが作れてしまう。標準の部品(ビューとコントローラ)を使うアプリであれば簡単にできる。ただし、Interface Builder を使って Cocoa Bindings の設定するのには、ちょっと慣れが必要だ。似たような設定項目が多く、設定する場所を間違えたら、まったく動かない。今日もそれでかなり苦労した。

参考文献

詳解 Objective-C 2.0
荻原 剛志
ソフトバンククリエイティブ ( 2008-05-28 )
ISBN: 9784797346800
Cocoa Programming for Mac OS X
Aaron Hillegass
Addison-Wesley Professional ( 2008-05-15 )
ISBN: 9780321503619

関連リンク

関連記事

twitter より (2010-11-24)

  • 16:23  そうか。何気なくアップデートしたけど、tv は iOS デバイスでありながら母艦を必要としないんだ。 → http://ipodtouchlab.com/2010/11/apple-tv-os41.html
  • 16:31  インタラクティブっていうのはデジタルコンテンツの得意とするところだものな。電子書籍もこっちの方向に進むかね。ただ、子どもに使わせるなら今の iPad はちょっと重すぎるだろう。 → http://bit.ly/gMJsry
Powered by twtr2src.

2010-11-24

日付文字列の変換 - RFC3339 から NSDate へ

実装

まずは、今回作った Objective-C による実装から示す。関数の機能は単純で、RFC3399 形式で表現された日時を元に NSDate のオブジェクトを生成する。関数内で NSDate オブジェクトを alloc しているが、返す前に autorelease しているため、荻原(2.0)本 (p.96) で言う「一時的なオブジェクト」となっている。また、関数を呼び出す側で自動解放プールを用意する必要がある。通常の Cocoa アプリの場合は、NSApplication がイベントループの管理とともに自動解放プールも用意してくれる(→ 「荻原(2.0)本」p.98)。

この実装では NSString の機能のうち、以下のメソッドを多用している。

- (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
aSet で渡された文字集合中の文字が最初に見つかった場所を返す。
- (NSString*)substringToIndex:(NSUInteger)aIndex
先頭から位置 aIndex までの部分文字列を返す。
- (NSString*)substringWithRange:(NSRange)aRange
aRange.location を開始位置とし、aRange.length を長さとする部分文字列を返す。
- (NSString*)substringFromIndex:(NSUInteger)
aIndex を開始位置としする末尾までの部分文字列を返す。

上記の substring...の戻り値はいずれも一時的なオブジェクトになっている。

参照仕様

GData API の Protocl Reference によれば、各種日付には RFC3339 フォーマットが使われる、とある。これは GData API が使うデータフォーマット(Atom 形式; RFC 4287 で定義されている)の仕様によるものだ。

(「RFC 4287」より)
A Date construct is an element whose content MUST conform to the "date-time" production in [RFC3339]. In addition, an uppercase "T" character MUST be used to separate date and time, and an uppercase "Z" character MUST be present in the absence of a numeric time zone offset.

[...snip...]

Example Date constructs:
<updated>2003-12-13T18:30:02Z</updated>
<updated>2003-12-13T18:30:02.25Z</updated>
<updated>2003-12-13T18:30:02+01:00</updated>
<updated>2003-12-13T18:30:02.25+01:00</updated>

上記の中で例として挙げられている 4 つのパターンを見れば書式のおよそは理解できる。

より詳細な 書式の定義は RFC 3339 にある。

date-fullyear   = 4DIGIT
date-month      = 2DIGIT  ; 01-12
date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on
                          ; month/year
time-hour       = 2DIGIT  ; 00-23
time-minute     = 2DIGIT  ; 00-59
time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second
                          ; rules
time-secfrac    = "." 1*DIGIT
time-numoffset  = ("+" / "-") time-hour ":" time-minute
time-offset     = "Z" / time-numoffset

partial-time    = time-hour ":" time-minute ":" time-second
                  [time-secfrac]
full-date       = date-fullyear "-" date-month "-" date-mday
full-time       = partial-time time-offset

date-time       = full-date "T" full-time

この定義から、日時の表現は「日付」と「時刻」に二分され、その区切りが文字「T」であること、また「時刻」は「時刻本体」と「時差」に分かれることが読みとれる。

「時差」については、時刻による差分で表現したもの(「+09:00」や「-5:00」など)か、あるいは文字「Z」を用いる(時差として文字「Z」を指定した場合、その時刻は UTC を意味する)。

さらに「時刻本体」の表現については、「時」「分」「秒」をそれぞれ 2 桁の十進数で表現する(1 桁の場合は先頭に「0」を付加する)。また「秒」については 1 秒以下を小数表現で「秒」に付けても良い、となっている。

GData API での時刻の取扱い

実際に GData API が返すフィードを見ると、updated 要素等は以下のようになっていて、確かに上記の書式に従っていることがわかる。

<published>2010-10-03T21:18:00.000+09:00</published>
<updated>2010-10-03T21:18:00.840+09:00</updated>

一方、GData Objective-C Library が返す時刻データは GDataDateTime クラスのインスタンスになっていて、そこから文字列データを取り出すと RFC3339 フォーマットの文字列となる。ただし、それを作る部分は以下のようになっているため、「秒数」の小数点以下が無視されている(GData Objective-C Client ver. 1.10.0)。これは、Cocoa の NSDateComponents が小数点以下の秒数をサポートしていないことによるものだと思われる(以下のコード中の dateComponents は NSDateComponents のインスタンスを保持している)。

- (NSString *)stringValue {
  return [self RFC3339String];
}

- (NSString *)RFC3339String {
  NSDateComponents *dateComponents = [self dateComponents];
  NSInteger offset = [self offsetSeconds];

  NSString *timeString = @""; // timeString like "T15:10:46-08:00"

  if ([self hasTime]) {

    NSString *timeOffsetString; // timeOffsetString like "-08:00"

    if ([self isUniversalTime]) {
     timeOffsetString = @"Z";
    } else if (offset == NSUndefinedDateComponent) {
      // unknown offset is rendered as -00:00 per
      // http://www.ietf.org/rfc/rfc3339.txt section 4.3
      timeOffsetString = @"-00:00";
    } else {
      NSString *sign = @"+";
      if (offset < 0) {
        sign = @"-";
        offset = -offset;
      }
      timeOffsetString = [NSString stringWithFormat:@"%@%02ld:%02ld",
        sign, (long)(offset/(60*60)) % 24, (long)(offset / 60) % 60];
    }
    timeString = [NSString stringWithFormat:@"T%02ld:%02ld:%0l2d%@",
      (long)[dateComponents hour], (long)[dateComponents minute],
      (long)[dateComponents second], timeOffsetString];
  }

  // full dateString like "2006-11-17T15:10:46-08:00"
  NSString *dateString = [NSString stringWithFormat:@"%04ld-%02ld-%02ld%@",
    (long)[dateComponents year], (long)[dateComponents month],
    (long)[dateComponents day], timeString];

  return dateString;
}

おまけ

最初に挙げたプログラムを Xcode で Command Line Tool としてビルドし、実行するとコンソールには以下のように出力される。水平線で区切られた 4 行が、testGetDateObject の一回の呼び出しによるもので、最初が引数として与えられた RFC3339 形式の日時文字列、2 行目が getDateObject による変換結果(の NSDate のインスタンス)、3 行目がそのインスタンスをデフォルトのタイムゾーン(ウチではもちろん JST)で評価した結果、最後の 4 行目は同インスタンスを UTC で評価した結果となっている。

2010-11-24 22:06:14.819 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.821 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56Z
2010-11-24 22:06:14.824 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.824 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.825 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000
2010-11-24 22:06:14.825 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.825 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56z
2010-11-24 22:06:14.826 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.826 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.826 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000
2010-11-24 22:06:14.827 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.827 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123Z
2010-11-24 22:06:14.827 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.828 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.828 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000
2010-11-24 22:06:14.828 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.829 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56.123z
2010-11-24 22:06:14.829 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.829 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900
2010-11-24 22:06:14.830 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000
2010-11-24 22:06:14.830 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.830 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56+09:00
2010-11-24 22:06:14.831 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.831 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.832 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000
2010-11-24 22:06:14.832 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.832 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56+09:00
2010-11-24 22:06:14.833 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.833 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.834 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000
2010-11-24 22:06:14.834 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.834 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123+09:00
2010-11-24 22:06:14.835 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.836 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.836 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000
2010-11-24 22:06:14.836 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.837 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12.34.56.123+09:00
2010-11-24 22:06:14.837 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.838 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900
2010-11-24 22:06:14.838 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000
2010-11-24 22:06:14.838 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.839 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56-05:00
2010-11-24 22:06:14.839 ExpApp[24929:a0b] NSDate object: 2010-11-23 02:34:56 +0900
2010-11-24 22:06:14.839 ExpApp[24929:a0b] Default TZ: 2010-11-23 02:34:56 +0900
2010-11-24 22:06:14.840 ExpApp[24929:a0b] UTC: 2010-11-22 17:34:56 +0000
2010-11-24 22:06:14.840 ExpApp[24929:a0b] ----------------------------------------
2010-11-24 22:06:14.840 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123-05:00
2010-11-24 22:06:14.841 ExpApp[24929:a0b] NSDate object: 2010-11-23 02:34:56 +0900
2010-11-24 22:06:14.841 ExpApp[24929:a0b] Default TZ: 2010-11-23 02:34:56 +0900
2010-11-24 22:06:14.842 ExpApp[24929:a0b] UTC: 2010-11-22 17:34:56 +0000

参考文献

詳解 Objective-C 2.0
荻原 剛志
ソフトバンククリエイティブ ( 2008-05-28 )
ISBN: 9784797346800

関連リンク

関連記事

twitter より (2010-11-23)

  • 18:13  iPad のアップデート中。アップデートが終わり、リブートした後の同期(バックアップ)に時間がかかるわ。雑誌の PDF データがでかいんだよね(Good Reader のデータになってる)。
  • 19:05  AirPlay って iPhone や iPad から tv への配信のみなのか。逆はできない。ちょっと残念だけど、これだけでもオモシロイ。iPhone や iPod touch ならリモコン感覚で使えるしな(実際リモコンにもなる)→ http://bit.ly/h97C0V
  • 19:06  AirPlay があると iPod touch に動画を溜めてみたくなる。
  • 21:17  そうだ、iPad のメールも iPhone と同じで「全受信」が使えるようになったんだね。これに慣れてしまうと、iPad でメールを開いたときにいちいちアカウントを切り替えるのがメンドウでしかたなかった。地味だけど、これも 4.2.1 になって良かったことの 1 つだな。
  • 21:34  お、いいね。.gitignore の設定集。プロジェクトごとだけじゃなく、グローバルに ignore を設定することもできるのね。OSX で git を使うときは便利だな。「.DS_Store」とか、いちいち足さなくても良くなる。→ http://bit.ly/fQxBqD
  • 21:51  今どきの若者や子どもたちの中にはダイヤル式の電話なんか見たこともなかったりするんだろうな。きっと使い方もわからないんだろうな。→ http://inspire.2ia.pl/post/35068946/dial-the-old-fashion-way
  • 21:55  ちょっと試してみたけど、おもしろかった。iPhone にも最適化されていて素敵。ただ、iPhone で開くとランダムボタンは出てこない。ちょっと残念。 → http://bit.ly/hLlA1V
Powered by twtr2src.