参考にしたのはこちら。
http://pojos-devlog.blogspot.com/2005/08/saving-animated-gif-using-coregraphics.html
iOS 4以降でよければImageIOフレームワークが使えるためむちゃくちゃ簡単です。任意のUIImage / CGImageRefから好きなようにアニメーションGIFを生成できます。
iOS 3以前の場合は・・・頑張れとしか・・・
2011年8月12日金曜日
メモ: CoreDataで更新処理をするときは、lockをわすれずに
単なるメモ書きです><
http://twitter.com/#!/akisutesama/status/83521489382555650
http://twitter.com/#!/akisutesama/status/83521729380626433
http://twitter.com/#!/akisutesama/status/83521489382555650
http://twitter.com/#!/akisutesama/status/83521729380626433
ある一つのCore Dataのモデルを非同期的に複数箇所から更新するときは、たとえどんなに軽微な、プロパティ一つだけの、他からは触られない様な変更ですら、きちんとlockを取らないと危険ということがわかった。API実行クラスだけでは不十分であった。非同期であればロック必須。
変更を行うコードブロックを渡して、内部で安全にロックして実行、必要に応じてロールバックや失敗通知も行える様にする仕組みを作ろうと思った。CoreDataのモデルオブジェクトの更新はただのsetterプロパティの使用だけで発生してしまうのでついつい忘れがちになるのですが、これが原因で実際にクラッシュしたアプリもあるので油断禁物。
UIPanGestureRecognizerはiOS4.0ではtranslationプロパティを正しく返さない
UIPanGestureRecognizerのtranslationプロパティは、iOS 4.0でかつUIScrollViewの配下になっているviewに対して取り付けた場合、常にCGPointZeroを返してしまうようです。iOS 4.1のシミュレータで確認したら直ってましたので、iOS 4.0限定だと思われます。というわけでvelocityプロパティをかわりに使っておくことをお進めします。
検証結果はこちら
検証結果はこちら
[NSObject load] と [NSObject initialize] の違い
クラスがObjective-Cのランタイムにロードされ利用可能になったタイミングで、そのクラス全体の初期化を行いたいということはよくあると思います。Objective-CではNSObjectクラスの以下のメソッドを用いてクラス全体の初期化を行うことができます。
http://cocoawithlove.com/2008/03/cocoa-application-startup.html
またloadメソッドについては、iOS実機で自家製frameworkを使っているを使っているとき、framework内部にビルドされているクラスのloadメソッドが呼び出されないという問題があります(静的ライブラリ.aについては未検証)iOSシミュレータおよびMacではきちんとframeworkに含まれているクラスについてもloadメソッドが呼び出されるのですが・・・ともかく地雷が大きいので避けたほうが懸命です。
- + load
- + initialize
http://cocoawithlove.com/2008/03/cocoa-application-startup.html
- loadメソッドはクラスがロードされて利用可能になったら即座に呼び出される。
- このとき、自分以外の他のクラスはまだロードされていない可能性があるので、自分以外のクラスを利用するような初期化はできない。
- main関数の内部のNSAutoReleasePoolが用意されるよりも先に呼び出されるので、autoreleaseを使うような初期化を行う場合には自分でNSAutoReleasePoolを生成して管理する必要がある
- initializeメソッドはそのクラスに実際のアクセスが最初に発生したタイミングで呼び出される。
- 要するに一度も使われないクラスでは呼び出されない。
- 自分以外のクラスもロードが完了しているので、自由に他のクラスを利用できる。
- autoreleaseについても特に気にしなくて良い。
またloadメソッドについては、iOS実機で自家製frameworkを使っているを使っているとき、framework内部にビルドされているクラスのloadメソッドが呼び出されないという問題があります(静的ライブラリ.aについては未検証)iOSシミュレータおよびMacではきちんとframeworkに含まれているクラスについてもloadメソッドが呼び出されるのですが・・・ともかく地雷が大きいので避けたほうが懸命です。
[UIView willMoveToSuperview:] が便利です
UIKitやFoundationには、iOS 2.0のころから存在するのに、意外と知られていない便利なメソッドやプロパティがたくさんあります。今回はUIViewのメソッドをご紹介します。
UIViewはUIViewControllerと違ってライフサイクルが単純で、どのタイミングで自分自身が画面上に追加されたのか、どのタイミングで自分自身が画面から外されたのか、などを把握しづらいとお嘆きの方がいらっしゃると思います。事実その用途のためだけにUIViewControllerを使ってプログラミングをしている人も見かけます。そこで以下のメソッドをご紹介です。
たとえば自作のUIViewで、画面にviewが追加されたタイミングで何かしたい・・・というときなどは以下のようにできます:
UIViewはUIViewControllerと違ってライフサイクルが単純で、どのタイミングで自分自身が画面上に追加されたのか、どのタイミングで自分自身が画面から外されたのか、などを把握しづらいとお嘆きの方がいらっしゃると思います。事実その用途のためだけにUIViewControllerを使ってプログラミングをしている人も見かけます。そこで以下のメソッドをご紹介です。
- willMoveToSuperview:
- 自分自身が新しいSuperview以下に移動しようとしたとき(新しいSuperviewに対してaddSubview:されようとしたとき)に呼び出されます。
- didMoveToSuperview
- 自分自身が新しいSuperview以下に移動したとき(新しいSuperviewにaddSubview:されたとき)に呼び出されます。
- willMoveToWindow:
- 自分自身が新しいWindow以下に移動しようとしたとき(新しいWindowに対してaddSubview:されようとしたとき)に呼び出されます。
- didMoveToWindow
- 自分自身が新しいWindow以下に移動したとき(新しいWindowに対してaddSubview:されたとき)に呼び出されます。
- didAddSubview:
- 自分自身に他のviewがsubviewとして追加されたときに呼び出されます。
- willRemoveSubview:
- 自分自身のsubviewsから他のviewが取り除かれようとしているときに呼び出されます。
たとえば自作のUIViewで、画面にviewが追加されたタイミングで何かしたい・・・というときなどは以下のようにできます:
- (void)willMoveToSuperview:(UIView *)newSuperviewこれでUIViewの使い勝手もアップ!ですね。
{
NSLog(@" * superview = %@", newSuperview);
NSLog(@" * superview's window = %@", newSuperview.window);
// UIViewControllerでいうところの loadView 兼 viewDidLoad 兼 viewWillAppear 兼 viewWillDisappearみたいなタイミング
}
- (void)didMoveToSuperview
{
// UIViewControllerでいうところの viewDidAppear 兼 viewDidDisappear みたいなタイミング
// ここで、もしsuperviewがあり(画面に表示される可能性があり)、まだ自分自身のデータが初期化されていない場合には
// reloadDataして初期表示データを読み込む
// superviewがない場合には画面から外されたのですべてのビューまわりをリセットして、次の表示に備えるようにしておく
if (self.superview) {
if (!self.someData) {
[self reloadData];
}
} else {
self.someData = nil;
[self __resetOutlets];
}
}
- (void)willMoveToWindow:(UIWindow *)newWindow
{
NSLog(@" * window = %@", newWindow);
// いまいち使いづらいのでwillMoveToSuperviewとかを使うようにしてます
}
- (void)didMoveToWindow
{
// いまいち使いづらいのでdidMoveToSuperviewを使うようにしてます
}
2011年8月9日火曜日
[UITableViewController scrollToRowAtIndexPath:atScrollPosition:animated:] の挙動まとめ
UITableViewController の scrollToRowAtIndexPath:atScrollPosition:animated: メソッドは、対象のテーブルビューのセクションにヘッダ・フッタが付いている場合挙動が変化する事がわかったので、ちょっと調査してまとめてみました。具体的には以下のような動きをするようです。
初期状態
section3つ、row3つ、合計9行のtable viewを作って、それぞれにsection header / section footerを追加しました。このテーブルビューを使って実験を行います。
UITableViewScrollPositionTopを指定してスクロール
UITableViewScrollPositionTopを指定すると、sectionの一番上のrowが指定された場合のみ、そのsectionのsection headerの高さを考慮してスクロールするようになります。
UITableViewScrollPositionMiddleを指定してスクロール
UITableViewScrollPositionMiddleの場合は特にsection header / section footer関係なく、中央に選択された行が来るようにスクロールするようです。
UITableViewScrollPositionBottomを指定してスクロール
UITableViewScrollPositionBottomを指定すると、sectionの一番下のrowが指定された場合のみ、そのsectionのsection footerの高さを考慮してスクロールするようになります。
- このメソッドは自分で呼び出すか、またはテーブルビューのセルの中に UITextField のようなフォーカスを取るコントロールを配置して、それが選択されたときに呼び出される
- このメソッドで指定した indexPath の section に Header View or Header Text / Footer View or Footer Text が指定されているとき、このメソッドは選択された indexPath の row だけではなく、それらのヘッダやフッタも同時に表示される位置にスクロールしようとする
- ということであんまり長い Section Header / Section Footer を作ると scrollToRowAtIndexPath:atScrollPosition:animated: の挙動がおかしくなる
- Table View Header / Table View Footer については全然無関係なので長くしても大丈夫
初期状態
section3つ、row3つ、合計9行のtable viewを作って、それぞれにsection header / section footerを追加しました。このテーブルビューを使って実験を行います。
UITableViewScrollPositionTopを指定してスクロール
| section0, row0 | ![]() | section0, row1 |
| section0, row2 |
|
| section1, row0 | ![]() |
UITableViewScrollPositionTopを指定すると、sectionの一番上のrowが指定された場合のみ、そのsectionのsection headerの高さを考慮してスクロールするようになります。
UITableViewScrollPositionMiddleを指定してスクロール
| section0, row0 | ![]() | section0, row1 | ![]() | section0, row2 | ![]() |
| section1, row0 | ![]() | section1, row1 | ![]() | section1, row2 | ![]() |
UITableViewScrollPositionMiddleの場合は特にsection header / section footer関係なく、中央に選択された行が来るようにスクロールするようです。
UITableViewScrollPositionBottomを指定してスクロール
| section0, row0 | ![]() | section0, row1 | ![]() | section0, row2 | ![]() |
| section1, row0 | ![]() | section1, row1 |
| section1, row2 | ![]() |
UITableViewScrollPositionBottomを指定すると、sectionの一番下のrowが指定された場合のみ、そのsectionのsection footerの高さを考慮してスクロールするようになります。
2011年8月5日金曜日
自分流 View Controllerの作り方 その2

その1はこちら
ぼくのかんがえたさいきょうのせっけいです
主に以下の書籍に影響受けまくりであります
![]() | Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler)) Martin Fowler Addison-Wesley Professional 2002-11-05 by G-Tools |
![]() | レガシーコード改善ガイド (Object Oriented SELECTION) マイケル・C・フェザーズ ウルシステムズ株式会社 翔泳社 2009-07-14 by G-Tools |
図を適当に補足
ViewWrapperは既存のすでにあるどうしようもない設計のViewを何とか救いたいときに非常に便利、Wraper / Decoratorパターンを適用してボタンのタップを奪い取ってViewHelperに流すみたいな役目をする
ViewHelperは簡単に言うならUITableViewControllerのdelegate, datasourceだけを担うオブジェクトみたいな感じ。要するにView専用のドメインロジックを書くオブジェクト
Viewの表示を制御するドメインロジックが途方もなく大きくてViewControllerに納めるのが不可能になってしまったときに超便利
Serviceは準ドメインロジックだと思っている、たいていの場合セミシングルトンみたいにする(通信が絡むので複数画面をまたいで使うことがほとんど)
Androidの場合はここ、普通にServiceクラスでいいんじゃないでしょうかね
Managerはドメインロジックというよりもプロセス外へのリソースアクセスを行うためのクラスというイメージ、個人的にはゲートウェイみたいな感じ
- NSFileManager
- NSUserDefaults
- KeychainAccessManager
- InAppPurchaseManager
- APIConnectionManager
と思ってましたがCoreDataのモデルは特にN:N関係を正しく扱わないと簡単に問題が発生してしまいますので、安易に採用すると危険かも。
Task, Operationってのは非同期で実行されていく特別なドメインロジックのイメージ。要するにAPI通信みたいなもんです
API通信を複数束ねて使ったりとか並列実行したりとかの制御が絶対必要になるのでそういうときに使う via @monjudoh
// MyTaskが終わったらMySuperTaskを実行して、それが終わったらさらにMySuperDuperTaskを連続して実行したい // 終わったらselfに通知させたい Task *root = [[[MyTask alloc] init] autorelease]; root.nextTask = [[[MySuperTask alloc] init] autorelease]; root.nextTask.nextTask = [[[MySuperDuperTask alloc] initWithId:100] autorelease]; root.delegate = self; [root start];
登録:
投稿 (Atom)

















