Jeanのブログ
Amebaでブログを始めよう!

後でファイル名を変更したくなった。AppDelegate.h/.mのファイル名を変更

http://boingboomchock.com/?p=25
いやぁ、すごく簡単でした。

ヘッダーファイル(.hファイル)の「@interface」の右にあるクラス名(xxxAppDelegateとか)を右クリックして、「リファクタリング」を選ぶだけ。

後は好きなファイル名を指定してOKクリックすれば終わりです。

アナログ時計の作り方解説ページ(4/4)

今回はxibの設定など。

AppDelegate.xibはとりあえず無視。

ViewController.xibですが、
Viewを削除して、
$Jeanのブログ

LibraryのClassesからAnalogClockを検索してドラッグ。
$Jeanのブログ

File's Ownerを右クリックして、clock、viewともに上記AnalogClockにドラッグ
$Jeanのブログ


AnalogClockのAttributesで背景を適当に灰色にしておきます。(時計の針が白なので)
保存して閉じます(これ忘れると期待通りにいかないです)。

Xcodeに戻って実行。
これで動くはずなのですが、シミュレーター上で結構落ちまくりでした。
それで、Xcodeから見れるコンソールからデバック繰り返していたのですが、この記事の作者のところからソースをダウンロードしたものと全く同じに見えるのになぁ。。と思って結構時間が経ってしまいました。たぶんCの基本がわかってないから原因究明もうまくできないんでしょう。

コンソールはAnalogClock classが認識できないというものでした。

とりあえず終わり。

iTunes U: RWTH iPhone App Programming

こちらは、私にはなんだか合わないみたい。
まずビデオ編集があまりされていなくて、待ち時間が長いのと、Xcodeの画面を移すのだけど、Mac上で見ても解像度が低くて何をやっているのかがいまいち確認できない。

他の方には参考になるかもしれないので、一応紹介しますが、個人的な評価は★☆☆☆☆です。

iTunes U - RWTH iPhone Application Programming

iTunes U: Stanford iPhone App Programming

自分が開発の「か」の字も知らない時から、わからないのを承知で見続けているビデオです。
同時進行で書籍なども読んでいますが、たまに見返すと、今まで何を言っているかわからなかった部分がわかったりして、成長度のチェックのような感じで活用しています。(英語ですけど)

Stanfordの公式サイトにはソースコードなどもあるので、活用次第ではないでしょうか。

iTunes University - Stanford iPhone Application Programming

アナログ時計の作り方解説ページ(3/4)

今回はApp DelegateとView Controllerをさくっと紹介。

### AppDelegate.h ###
### AppDelegate.m ###
何にも変更してないです。



次はViewController。

### ViewController.h ###
#import
#import "AnalogClock.h"

@interface AnalogClockViewController : UIViewController
{
IBOutlet AnalogClock* clock;
}

@end


基本的にAnalogClock Classを呼んで、AnalogClock宣言して終わり。

### ViewController.m ###
#import "AnalogClockViewController.h"

@implementation AnalogClockViewController

- (void) viewWillAppear:(BOOL)animated
{
[clock startClockUpdates];
}

- (void) viewWillDisappear:(BOOL)animated
{
[clock stopClockUpdates];
}

- (void)dealloc
{
[super dealloc];
}

@end


というわけで、ViewWillAppearとViewWillDisappearでAnalogClockのメソッド呼んで終わり。

次はxib関連の設定やります。

Unknown Class <クラス名> in Interface Builder file 2

エラー対策その2
Unknown Class <クラス名> in Interface Builder fileエラーですが、他の方法を紹介。

明示的にクラスを読み込むという方法です。

- (void) viewDidLoad
{
[super viewDidLoad];
[<クラス名> class];
}


って感じなんですが、これもだめだった。。

Unknown Class <クラス名> in Interface Builder file エ

コンソールでバグのチェックをしていると、"Unknown Class %lt;クラス名> in Interface Builder file"というエラーが出た。

検索してみると、
http://support.mobclix.com/forums/65895/entries/95353というのが出てきた。

プロジェクト < プロジェクト設定を編集 < ビルド で、構成を「すべての構成」にすると出てくる、リンクの項目にある「他のリンカフラグ」に「-ObjC」を入れるというもの。

今回のケースでは、役に立たなかったけど、いつか役に立つかな。。。

アナログ時計の作り方解説ページ(2/4)

さて、前回の続き。時計の針を作る部分です。

### AnalogClock.m ###
#import "AnalogClock.h"
#import <QuartzCore/QuartzCore.h>

@implementation AnalogClock

inline double rad(double deg)
{
return deg / 180.0 * M_PI;
}

- (void) drawLineForContext:(const CGContextRef&)context Width:(float)_width angle:(double)_angle length:(double)radius
{

CGPoint c = CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0);

CGContextSetLineWidth(context, _width);
CGContextMoveToPoint(context, self.center.x, self.center.y);
CGPoint addLines[] =
{
CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0),
CGPointMake(radius*cos(_angle) +c.x, radius*sin(_angle) +c.y),
};

CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0]));
CGContextStrokePath(context);

}


drawLineForContextというfunctionでたぶん時計針の描画してるんですね。
CGPoint cは画面の中心を求めています。CGPointMakeはx,y軸それぞれの2点を挿入して座標を求めます。

CGContextSetLineWidth(context, _width);は時分秒の針の太さを指定する部分。
次の行のCGContextMoveToPoint(context, self.center.x, self.center.y);で描画の開始点を指定、CGContextAddLinesで次の(といっても最終の)描画点を指定、CGContextStrokePathで描画するってな感じになってます。

次はdrawRectで上記ソースの続きです。

- (void)drawRect:(CGRect)rect
{

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate* now = [NSDate date];
int h = [[cal components:NSHourCalendarUnit fromDate:now] hour];
int m = [[cal components:NSMinuteCalendarUnit fromDate:now] minute];
int s = [[cal components:NSSecondCalendarUnit fromDate:now] second];
[cal release];

BOOL isAM = h<12;
double hAlpha = rad((isAM?h:h-12)*30 +(30*m/60) -90);
double mAlpha = rad(m*6 -90);
double sAlpha = rad(s*6 -90);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
[self drawLineForContext:context Width:8.0 angle:hAlpha length:self.frame.size.width/2.0 - 18];
[self drawLineForContext:context Width:5.0 angle:mAlpha length:self.frame.size.width/2.0 - 12];
[self drawLineForContext:context Width:2.0 angle:sAlpha length:self.frame.size.width/2.0 - 10];

}


NSCalendarから始まる行~[cal release]は現在の時、分、秒を取得しています。ちなみにalloc initしている場合は必ずreleaseした方がいい(と理解してます)。

BOOL isAM = h<12;は時間が24時間制なので、12時間表示にするために、時間が12を超えるとフラグが立つようにしています。
hAlpha、mAlpha、sAlphaではそれぞれの時計の針の角度を求めています。(ここで前回のrad関数を使用してます)

その下は時、分、秒針を上記drawLineForContextを利用してそれぞれ描画しています。(だんだん雑になってきた?実はあまりわかってないのかも)

では次、AnalogClock.mの残りの部分です。

-(void)update
{
[self setNeedsDisplay];
}

-(void)startClockUpdates
{
[self update];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(update) userInfo:nil repeats:YES];
}

-(void)stopClockUpdates
{
[timer invalidate], timer = nil;
}

-(void)dealloc
{
[self stopClockUpdates];
[super dealloc];
}

@end


updateにあるsetNeedsDisplayがないと秒針が進まないです。Class ReferenceにはdrawRectを呼び出さずに自動でviewが再表示(つまり更新?)されるということらしいです。

startClockUpdatesは1秒ごとに上記updateが呼ばれるように設定。
stopClockUpdatesは上記を終了。
deallocは、... ここでstopClockUpdatesを呼んでいますね。私はあまり見たことがない形です。

次回はAppDelegateとViewControllerの設定かな。

const

const修飾子
「onstを付けられた変数は、初期化はできますが、その後の代入ができなくなります。つまり、1度保持した値を 上書きできない変数になります。」
「constは、記号定数のように使えるので、変数名を大文字で書くことが多いです。#defineで定義した記号定数と違い、 はっきりした型が指定できるのが優れています。constはポインタにも使えますが、次の2つの宣言は意味が異なるので 注意して下さい。」
なるほど。。

Objective-Cにおけるenumとconstの差異が分からない

アナログ時計の作り方解説ページ(1/4)

英語ですけど、ソースもダウンロードできます。

最初シミュレーターでエラーが出たけど、"Simulator - 3.1.2"を選択してビルドしたらできました。

App DelegateはAnalogClockViewControllerを呼んでいるだけ。
AnalogClockViewControllerもAnalogClockのClassを呼んで、viewWillAppearとviewWillDisappearメソッドでそれぞれスタートとストップを実行しているだけ。

で、そのAnalogClock Classですが。。。
(あ、プログラムのわかる人はさっさと、上記ソースダウンロードして見て下さいね。下記はずかしいので見ないで)




とりあえず、真似してみます。

1. View-based Applicationでプロジェクト作成、FrameWorkフォルダで右クリックして「既存のフレームワーク」からQuartzCoreを追加

2. 新規ファイル追加で、Object-C Classを作ります。真似して「AnalogClock.h」(UI Viewのサブクラス)を作成

### AnalogClock.h ###
#import

@interface AnalogClock : UIView
{
NSTimer *timer;
}

-(void)startClockUpdates;
-(void)stopClockUpdates;

@end


結局コピペと同じ状態ですね。。汗)
NSTimerは、時間を管理するClassですね。
-(void)で始まる2行は、mファイルで実装しまっせ、という宣言。

気を取り直して次。
### AnalogClock.m ###
#import "AnalogClock.h"
#import

@implementation AnalogClock

inline double rad(double deg)
{
return deg / 180.0 * M_PI;
}


Cが素人な私はinline doubleとかなんのこっちゃという感じです。
Wikipediaによるとinline関数とは"インライン関数(Inline Function)とは、プログラミング言語の構文の一種で、コンパイラに対して特定の関数をインライン展開するよう指示するものである。つまり、コンパイラに対して、その関数を呼び出している全ての箇所に関数の実体を挿入するよう指示する。"とのこと。さっぱりわかりません。
いろいろ調べると、とりあえず「オーバーヘッドが軽くなる」ということで、そのままfunctionを定義するものらしいので、基本的には、rad(double deg)という関数を定義してあるということですね。(間違っていたらごめんなさい)
まぁ、AnalogClock.mの後半にradという関数で時分秒を計算しているっぽいので、こんな理解で大丈夫でしょう。

return deg / 180.0 * M_PIの行は、角度(degree)をラジアンに直すという作業を行ってますね。
M_PIはパイ(円周率)です。

Google先生に聞いて、ラジアンをなんとなく理解。(てか、ここら辺知らずに時計アプリ作ろうとしている自分が怖い。。)

長くなってきたのでとりあえず、ここで終了。。。