MacBook Pro earlyに2011を載せてみた。うわさ通りレインボーカーソルがまわってフリーズしたようになった。ので、ファームウェアをアップデートしてみることにした。
Macでのアップデートのやり方の情報がすくなかった。少ない情報から以下のようにやってみた。
Crucial.com Product Downloads – Firmware Updatesからm4用のファームウェアisoをダウンロードしてDVDを作成。MBP early 2011ではアップデートができないらしいので、以前使っていたMacBookにm4をとりつける。DVDから起動して、指示に従う(yesを入力するくらい)。アップデート終了したらm4をMBPにとりつける。
以上で完了。レインボーカーソルが表示されることがなくなり、とても快調になった。
Lionにzshをインストールした。以前もやったのだが、記録がなかったのでとどめておく。
zshをHomebrewでインストールする。
/ect/shellsに/usr/local/bin/zshを追加する。
システム環境設定の「ユーザとグループ」を開く。鍵を開く。
シェルを変更したいユーザを右クリックして詳細オプションを開く。
ログインシェルを/usr/local/bin/zshに変更する。
Safari5.1になってEvernoteクリッパープラグインが使えなくなっていますね。
しかたがないので、そのうち対応されることでしょうからそれまでの間はブックマークレットを使用してクリップすることにします。
追記: Safari 5.1からEvernoteにPDFで保存する方法について記事を書きました。
ImageMagickとRMagickを使うべくhomebrewとgemでインストールした。
$ brew install imagemagick
$ gem install rmagick
で、使ってみるとSegmentation faultがでる。検索した結果、以下のように再インストールすれば使えるようになった。
brew install -f imagemagick --disable-openmp
つぎにannotationを使おうとするとフォントが無いと言われる。ので
ftp://ftp.imagemagick.org/pub/ImageMagick/delegates/ghostscript-fonts-std-8.11.tar.gz
をダウンロードして、以下のように/usr/local/share/ghostscriptに展開する。
$ mkdir /usr/local/share/ghostscript
sudo tar xzf ghostscript-fonts-std-8.11.tar.gz -C /usr/local/share/ghostscript
これでやっと利用できるようになった。
Xcode4になってUserInterfaceState.xcuserstateファイルが作成されるようになった。これがくせ者でXcodeを触るとすぐに変更されてしまって、gitで管理しているとコミットかチェックアウトしないといけなくなってしまう。
ので.gitignoreに加えた。
で、加えるだけでは駄目で、
git rm --cached ProjectFolder.xcodeproj/project.xcworkspace/xcuserdata/myUserName.xcuserdatad/UserInterfaceState.xcuserstate
git commit -m "hoge"
とする必要がある。
KeyRemap4MacBookで「かな」キーをコントロールキーにしてみた。
これまでは小指でコントロールキーを押していたけど、親指でおせると少しは楽かもしれない。
親指シフトを使っていて英数キーは親指シフトキーなのでコントロールにはできない。コントロールにするには英数キーの方があっているかもしれない。かなキーだとCtrl-Mが押しにくい。それは我慢ということで。
UINavigationControllerでビューコントローラーをpush/popするときのアニメーションはスライドです。このアニメーションをカスタマイズしてみます。
ここではフェードを行ってみます。
まずはpushです。
- (IBAction)push {
SubViewController *subViewController = [[[SubViewController alloc] initWithNibName:nil bundle:nil] autorelease];
subViewController.view.frame = self.view.bounds;
subViewController.view.alpha = 0.0;
[self.view addSubview:subViewController.view];
[UIView transitionWithView:subViewController.view duration:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void) {
subViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
[self.navigationController pushViewController:subViewController animated:NO];
}];
}
pushする対象はSubViewControllerです。現在のビューと同じサイズに設定して、透明にして、現在のビューにaddSubviewします。
アニメーションですが、alphaを1.0にして不透明にします。アニメーションが完了したらpushViewController:animated:でpushを行います。animatedにはNOを指定して、デフォルトのスライドアニメーションを行わないようにします。
次にpopです。
- (IBAction)pop {
NSArray *viewControllers = [self.navigationController viewControllers];
NSUInteger previousIndex = [viewControllers count] - 2;
UIViewController *previousViewController = [viewControllers objectAtIndex:previousIndex];
previousViewController.view.alpha = 0.0;
[self.view addSubview:previousViewController.view];
[UIView transitionWithView:previousViewController.view duration:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^(void) {
previousViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
[self.navigationController popViewControllerAnimated:NO];
}];
}
viewControllers から、pop後に表示される前のビューコントローラーを取得します。viewControllers配列の後ろから2番目に入っています。このコントローラーのビューのalphaを0.0に設定して透明にして、現在のコントローラーのビューに載せます。
アニメーションも同様にalphaを1.0に設定して、不透明にします。アニメーションが終了したらpopViewControllerAnimated:でpopします。これもNOを指定してデフォルトアニメーションを行わないようにします。
このように、UINavigationControllerでのフェードアニメーションは、push/popはどちらも、これから表示するビューを上に載せて、透明から不透明にアニメーションを行い、アニメーションが終了したタイミングでpush/popを行うことになります。
基本的にはNSManagedObjectContextはスレッド毎に作成して利用しなければいけません。以下は、その為にスレッド毎にContextを作成して管理するためのコードです。複雑なアプリでなければ、この管理法で十分でしょう。シングルトンなManagerクラスでコンテキストを管理する方法は簡単ですが、スレッドを多用する場合はスレッド毎に管理する方が良いでしょう。
managedObjectContextForCurrentThreadでコンテキストを取得し、保存は[NSManagedObjectContext save:&error]のように、クラスメソッドを呼びます。保存するとNSNotificationでコンテキスト自身のmanagedObjectContextDidSave:が実行され、メインスレッドのコンテキストに変更が反映されます。スレッド毎に自動的にthreadDictionaryにNSManagedObjectContextを登録し、スレッドが破棄されるとコンテキストも破棄されるようになっているので、明示的にコンテキストを破棄する必要はありません。
@interface NSManagedObjectContext (Extras)
+ (NSManagedObjectContext *)managedObjectContextForThread:(NSThread *)thread;
+ (NSManagedObjectContext *)managedObjectContextForCurrentThread;
+ (NSManagedObjectContext *)managedObjectContextForMainThread;
+ (BOOL)save:(NSError **)error;
@end
#import "NSManagedObjectContextExtras.h"
NSString * const NSManagedObjectContextThreadKey = @"NSManagedObjectContextThreadKey";
@interface NSManagedObjectContext ()
- (void)managedObjectContextDidSave:(NSNotification*)notification;
@end
@implementation NSManagedObjectContext (Extras)
+ (NSManagedObjectContext *)managedObjectContextForThread:(NSThread *)thread {
NSMutableDictionary *threadDictionary = [thread threadDictionary];
NSManagedObjectContext *context = [threadDictionary objectForKey:NSManagedObjectContextThreadKey];
if (!context) {
#ifdef TARGET_OS_IPHONE
id appDelegate = [[UIApplication sharedApplication] delegate];
#else
id appDelegate = [NSApp delegate];
#endif
NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];
if ([[NSThread currentThread] isMainThread]) {
context = mainContext;
} else {
context = [[[NSManagedObjectContext alloc] init] autorelease];
[context setPersistentStoreCoordinator:[mainContext persistentStoreCoordinator]];
}
[threadDictionary setObject:context forKey:NSManagedObjectContextThreadKey];
}
return context;
}
+ (NSManagedObjectContext *)managedObjectContextForCurrentThread {
return [NSManagedObjectContext managedObjectContextForThread:[NSThread currentThread]];
}
+ (NSManagedObjectContext *)managedObjectContextForMainThread {
return [NSManagedObjectContext managedObjectContextForThread:[NSThread mainThread]];
}
+ (BOOL)save:(NSError **)error {
NSManagedObjectContext *context = [NSManagedObjectContext managedObjectContextForCurrentThread];
BOOL isMainThread = [[NSThread currentThread] isMainThread];
if (!isMainThread) {
[[NSNotificationCenter defaultCenter] addObserver:context
selector:@selector(managedObjectContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:context];
}
BOOL result = [context save:error];
if (!isMainThread) {
[[NSNotificationCenter defaultCenter] removeObserver:context
name:NSManagedObjectContextDidSaveNotification
object:context];
}
return result;
}
- (void)managedObjectContextDidSave:(NSNotification*)notification {
NSManagedObjectContext *context = [NSManagedObjectContext managedObjectContextForMainThread];
[context performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
}
@end
「クラウド」は正式(?)にはクラウドコンピューティングといい、どちらかというとネットワークとハードウェアのハンドリングについて意味する言葉です。ネットワーク・コンピューティングを言い換えただけで宣伝文句がかわっただけという指摘もあるくらいです。
iCloudもネットワークやハードウェアはたしかに「クラウド」になっています。が、それだけではないシステムのようです。データのハンドリングまで雲の中に隠れて行ってくれるようになっているようです。「クラウド」はネットワークやハードは雲の中に隠れていましたが、ユーザはデータの同期などまだまだ意識する点がありました。iCloudは目の前のデータすら雲に入れて、「体験する」クラウドを提供することになるのではないでしょうか。
つまりiCloudは、これまで言い換えただけといわれていたハード中心の「クラウド」から、体験としてのクラウドに「進化」したといえるのではないでしょうか。
(まぁ、使ってみないことには分からないですけどね。)