CoreData でいきなりエラーの対処方法
CoreData アプリを作ろうと、Master-Detail テンプレートで use coredata する。
テンプレートの通り、変更なしで build すると問題なし。
次に、CoreData の entity を追加して build するとエラー・・・
たったこれだけでエラー・・・
敷居高いね・・・(お高くとまりやがって、あ、愚痴言いました、ごめんなさい)
初回起動時に sqlite などのデータが作られますが、entity の変更を行うと整合が取れなくなってしまうようです。
このエラーの回避方法は次の通り。
1. simlator のアプリを削除
2. その上で、再度 build
あー、CoreData 苦手・・・
delegate とは何か(5)
具体的に delegate を使うように記述します。
STtouchPointCircle は、丸の class です。
STtouchPointCircle.h
#import <UIKit/UIKit.h>
@class STtouchPointCircle;
@protocol STTouchPointCircleDelegate
- (void) beginImageTouched:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) duringTouchPoint:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) endTouchPoint:(NSSet *)touches withEvent:(UIEvent *)event;
@end
@interface STtouchPointCircle : UIView
@property (weak) id delegate;
@end
はじめに、@class でクラス名を規定します。この記述は必須ではありませんが、明示した方が後でわかりやすいので記述しています。
@protocol 部分は通知(delegate)の名前と、method 名を記述します。
ここで特徴的なのは、@protocol - @end の間に宣言した method は、このクラスでは実装しない点です。
次に実装部分です。
STtouchPointCircle.m
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
if ([self.delegate respondsToSelector:@selector(duringTouchPoint:withEvent:)])
{
[self.delegate duringTouchPoint:touches withEvent:event];
}
}
丸をタッチしている最中、touchesMoved: メソッドが呼ばれます。
ここで、delegate を通じて header で定義した method を呼び出しています。
丸のクラスでは header で method 名を宣言していて、実装部では呼び出しを行いますが、この method の具体的な記述は UIViewController.m で行います。
delegate の意味を辞書で調べると委託、委任などの意味であることがわかります。自身の class には宣言だけしておいて実装がなく、別の class に実装がなされることに由来した命名であることがわかります。
次に、UIViewController を見てみます。
UIViewController.h
#import <UIKit/UIKit.h>
#import "STControlPoint.h"
@interface ViewController : UIViewController<STTouchPointCircleDelegate>
@end
呼び出し元である STControlPoint.h を import します。
次に、@interface 部分で、<STTouchPointCircleDelegate> を記述し、この class が反応する protcol を記述します。この記述があることで、STTouchPointCircle が呼び出しを行うと、このクラスが反応することになります。
前に、delegate とは「赤ちゃんがオムツを替えてくれと泣くようなもの」と記載しましたが、とてもよく形容していると思います(ただ、赤ちゃんが泣くと皆が反応してしまい、人前だと親としては恐縮してしまうこともあるのですが、delegate の場合、protocol を通してあれば反応する、換言すると、protcol を通していないと反応しないという部分が違います。赤ちゃんが泣く例もそうだとよいのですが・・・)。
次に、実装部分を見てみます。
UIViewController.m
- (void) duringTouchPoint:touches withEvent:event
{
CGPoint newLocation = [[touches anyObject] locationInView:self.canvas];
CGPoint oldLocation = [[touches anyObject] previousLocationInView:self.canvas];
CGFloat deltaX = newLocation.x - oldLocation.x;
CGFloat deltaY = newLocation.y - oldLocation.y;
UITouch* touch = [touches anyObject];
...some codes...
}
STtouchPointCircle.h で宣言した method を、UIViewController.m で実装しています。
このように、delegate では宣言した class とは別の calss に実装します。
delegate とは何か(4)
ところで、丸をタッチしたら・・・という記述をしたいので、UIViewController.m の touchesBegan に記載を行いましたが、よく考えてみると、丸に関する記述なので、丸の class に記述を行うのが正しい姿なのではないだろうかと思いませんか。
オブジェクト指向とは何か?という議論は様々なところでなされていますが、そういった解説を読みオブジェクト指向に詳しい人ほど強くそう思うでしょう。
この考えは正しくて、丸の挙動に関する記述なので、丸の class に動作を書くべきです。
一方、UIViewController.m に記述することもあります。
それは、丸の特例として UIViewController.m だけで特殊な動作をさせたい、あるいは、この場合に限って丸の動作を拡張したいといった場合です。
今回の事例ではそのような特例の考慮は必要なく、丸に関して常に同一の動作でよく、換言すると、丸固有の動きとして規定したいので丸の class に記述することが妥当だということになります。
つまり、丸をタッチしたらどのような動きをしてほしいか、丸について統一的に規定しておきたい、ということです。
動作はこうなります。
・ユーザは丸をタッチし動かす
・動かした量に応じて丸を移動する
これを実現するには、次のような記述になります。
・ユーザが丸をタッチすると、丸の calss の touchesMoved が反応する
・ユーザが丸の移動を終えると、UIViewController が反応し、丸を移動し再描写する
通常、method はオブジェクトに対して message を送るなどと形容されます。
上記の例では、丸の class から UIVewController に対して message を送るような形をとります(厳密には、オブジェクトを指定せず通知を送っている)。
では、具体的にどのように記述するのでしょう。
続く。
delegate とは何か(3)
ViewController.m だけで記述できるけれども delegate を使ったほうがよいと書きました。
それはなぜでしょう。
理解を促進するために、ViewController.m に記述するとどうなるか試してみます。
- (void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event
{
UITouch* touch = [touches anyObject];
if ( [touch.displayNumber isEqual: @"1"] )
{
some codes...
}
else if ( [touch.displayNumber isEqual: @"2"] )
{
some codes...
}
else if ... 以下続く...
}
以上のようになります。
画面上にある丸であればまだよいのですが、丸は削除したり追加したりできるので、あらかじめ記述できないものも出てきます。
そのような理由により、書きようがないので delegate を使うということになります。
この説明は明快だと思います。
これとは別の視点で、ViewController.m に書かない方がよいとの判断もあります。
続く。
delegate とは何か(2)
delegate は必要性があっての概念なのですが、その必要性が分かっていないとなかなか理解が進みません。
必要性を理解するために、具体的な事例をもとにして整理してみたいと思います。
次のようなアプリを考えます:
・ユーザは画面上の丸を頻繁に動かします
・ユーザが動かした丸に応じて、画面上で描写が変化します
・ユーザは必要に応じて丸を追加したり削除したりできます
画面上の、オレンジと黄色の丸はユーザーが動かすことができます。
さて、オレンジと黄色の丸はどのように生成するでしょう。
通常、オレンジの丸、黄色の丸それぞれクラスを作り、ViewController.m 辺りに、初期表示用のコードを記載し画面上に表示します。
表示されているオレンジも黄色もそれぞれユーザは任意に動かすことができます。
ユーザが丸を動かすと、ViewController の touchesBegan:withEvent メソッドや touchesMoved:withEvent メソッドが呼ばれます。
どの丸を動かしても ViewController の同じメソッドが呼ばれることが、以降を理解する上で重要です。
つまり、オレンジの 0 を動かしたときとオレンジの 1 を動かしたときに同じメソッドが呼ばれることになります。
同じメソッドが呼ばれることから、プログラムを作成する上ではユーザがどのオブジェクトを操作した結果、そのメソッドが呼ばれたかを判別する必要が出てきます。
touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event とメソッドは定義されているため、touches には引数として、操作したオブジェクトが含まれているので名前や tag を取り出すことで判別できることになります。
つまり、delegate を使わなくても、ViewController.m だけでプログラミング可能ということになりますが、それでもなお、delegate を使ったほうがよいのです。
それはなぜでしょう。
続く。
delegate とは何か(1)
オブジェクト指向プログラミングのテクニックで delegate と呼ばれるデザインパターンがあります。
iOS のアプリを作るときには頻繁に利用することになるのですが、最近ようやく意味が分かってきた、というより、初めからこれを分かっていないと iOS のプログラムを組みにくいと思う。
残念ながら私は初めから分かっておらず、試行錯誤の末にようやく理解するに至ったわけですが、時間が経ってまた分からなくなったら参照できるように、記しておこうと思います。
delegate とは、辞書を引くと「代理人」、「委任」、「委譲」などの意味であることがわかります。
デザインパターンの delegate が分かってしまえば、「あーなるほど」と思うのですが、初学者にはとてもわかりにくい概念です。
私もはじめは主にネットの情報を調べて、必要に応じてプリントしたりしてなんども読み直したりしたのですが、他の方の説明では、
・赤ちゃんがオムツでクソしたからケツ拭いてくれと泣くようなもの
・protcol を通じた通知
など、これまた、分かってしまえばその通りなのですが、分かっていないうちは??でした。
なぜ自身が理解できなかったかというと、必要性があっての delegate なのですが、その「必要性」を理解していなかったからだろうと思います。
続く。
App Store のレビューに要する期間がずいぶん短くなった。
先日、BezierCurveAnimation II を無事リリースししました。
AppStore に上市するには Apple の Review があり、その後リリースとなります。
去年ぐらいは review の期間が 1 週間ぐらいかかっていたのだけれど、今回は提出から 36 時間ほどで上市となりました。
いつも、どれくらい時間がかかるのかわかるサイトで確認していますが、他の方もずいぶん短くなっている様子。
Average App Store Review Times
よいことですね。