カスタム検索

2008年12月31日水曜日

iPhoneで動かすHelloWorld その4

インフルエンザで死んでおります・・・胃が痛い(T_T)
高熱でちょっと忘れかけておりますが、日々の積み重ねが大事です!

ではViewControllerの実装です。

MyViewController.m で警告が出ているはずです。
MyViewController.h で property 指定した textField , label , string に対するメソッドがないという事なので、アクセサメソッドの実装をしてやります。


@synthesize textField;
@synthesize label;
@synthesize string;


これらのインスタンス変数が正しく解放されるように dealloc に追記します。


- (void)dealloc {
[textField release];
[label release];
[string release];
[super dealloc];
}


ボタンを押させると changeGreeting がコールされる所まで確認しましたので、ここでテキストフィールドから文字列を取得し、ラベルを書き換えるようにします。


- (IBAction)changeGreeting:(id)sender {
self.string=textField.text; // textFieldから文字列を取得し、自身のstring変数に格納します。

NSString *nameString=string;
if([nameString length]==0) {
nameString=@"World"; // textFieldの文字列が空なら World を代入する
}
NSString *greeting=[[NSString alloc] initWithFormat:@"Hello, %@!",nameString]; // ラベルに表示するメッセージを作成
label.text=greeting;
[greeting release];
}


ここまででビルドすると、以下のような結果が得られます。



大筋は完了しましたが、キーボードが閉じられない事に気がつくでしょう。
MyViewController.m に以下のコードを追記します。


- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
if(theTextField==textField) {
[textField resignFirstResponder];
}
return YES;
}


再度実行すると、Doneでキーボードが隠れる事を確認できます。

以上で完成です!思ったより長かったです・・・体が痛い(T_T)

2008年12月27日土曜日

iPhoneで動かすHelloWorld その3

Viewに物をおいてみましょう!

ControllerView.xib をインターフェースビルダーで起動して、LibraryからTextField と Label と Round Rect Button を配置します。
↓こんな感じです。



各Objectの設定はInspectorパネルから色々操作出来ます。
TextのInspectorを見ると、TextInputTraitsという項目があって、ここでキーボードの形や、決定ボタンの形などが調整出来ます。

ここでシミュレーターで実行してみると、キーボードは開きますが、消す事が出来ない状態です。
これはキーボードの終了イベントを受け取る場所がないのでキーボードが閉じられないというわけです。

このイベントをMyViewControllerと関連付けします。
関連付けはアウトレットというインスタンス変数によって行われます。

MyViewController.h

#import

//MyViewControllerはテキストフィールドのデリゲートになるため、UITextFieldDelegateプロトコルを採用する必要があります。
//プロトコルの指定はクラスの継承元クラスの後に <> で指定します。
@interface MyViewController : UIViewController {

//IBOutletは、続く宣言をアウトレットとして使う。という指示です。
IBOutlet UITextField *textField;
IBOutlet UILabel *label;
NSString *string;
}

//@propertyでgetter,setterをproperty定義します。
@property (nonatomic, retain) UITextField *textField;
@property (nonatomic, retain) UILabel *label;
@property (nonatomic, copy) NSString *string;

//Helloボタンを処理するchangeGreetingメソッドを定義します。
//IBActionは、続く宣言をターゲット/アクション接続のアクションとして扱う。という指示です。
-(IBAction)changeGreeting:(id)sender;

@end


実装クラスへメソッドの中身を定義します。

MyViewController.m

- (IBAction)changeGreeting:(id)sender {
printf("call!");
}


保存してインターフェースビルダーへ戻り、File's OwnerのIdentity Inspectorをみると、
Class ActionとClass OutletsにchangeGreetingとlabel,textFieldが追加されています。
これはMyViewControllerクラスがControllerViewのビュークラスとして指定されている為です。

インターフェース上に設置されたオブジェクトとフィールドを関連付けます。
File's Ownerを右クリックして出てきたリストから○をドラッグして、関連付けたいオブジェクトへドロップします。

ボタンのアクションをファンクションへ関連付けます。
ボタンをCTRL+クリックで出てくるInspectorの中からTouch Up Insideの○をFile's Ownerへドラッグ&ドロップします。
changeGreetingが表示されるのでそれを選択する事で関連付けが行われます。

テキストフィールドのデリゲートを設定します。
テキストフォールドをCTRL+ドラッグでFile's Ownerへドロップします。
選択肢からDelegateを選ぶ事でデリゲートの設定が行われます。

ここまで設定したら一度実行してみます。
ボタンを押してコンソールにcall!が表示されたら連携がうまくいっています!
次は実際に処理を書いていきます。(まだまだキーボードは戻せません :p)

2008年12月25日木曜日

iPhoneで動かすHelloWorld その2

Viewを追加するにはViewControllerとnibファイルを使用します。

まずはViewControllerの作成です。
Xcodeから新規ファイルで CocoaTouchClasses の UIViewControler subclass を選択します。
テンプレートを元にざっくりとファイルが生成されます。

作成したクラスをアプリケーションデリゲートのインスタンス変数に追加します。

作成したクラスをMyViewControllerとし、HelloWorldAppDelegateへ以下のように定義します。

HelloWorldAppDelegate.h

#import
@class MyViewController; // クラス宣言

@interface HelloWorldAppDelegate : NSObject {
UIWindow *window;
MyViewController *myViewController; // 追加したビューをインスタンス変数として定義します
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) MyViewController *myViewController;

@end


HelloWorldAppDelegate.m

#import "HelloWorldAppDelegate.h"
#import "MyViewController.h" // インポート宣言

@implementation HelloWorldAppDelegate

@synthesize window;
// アクセサメソッドの合成?
@synthesize myViewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
// ViewControllerの作成、ControllerView.nibをターゲットとします。bundleはresouceの位置的な情報?
MyViewController *aViewController = [[MyViewController alloc]initWithNibName:@"ControllerView" bundle:[NSBundle mainBundle]];
// デリゲータのmyViewControllerに上で作成したインスタンスを指定
self.myViewController=aViewController;
// 一時インスタンスの解放
[aViewController release];

// myViewControllerからviewを取得
UIView *controllersView=[myViewController view];
// windowへControllerViewのviewを追加
[window addSubview:controllersView];

[window makeKeyAndVisible];
}

- (void)dealloc {
[myViewController release]; // デリゲートが解放される時(アプリ終了時)にビューを一緒に解放します
[window release];
[super dealloc];
}

@end


ビューを作成します。
InterfaceBuilderを起動して新規作成>CocoaTouch>Viewでビューが作成できます。
ControllerView.nib としてHelloWorld プロジェクトに保存します。
Xcodeが立ち上がっていれば、自動的にリソースとして取り込むか選択が出ます。
リソースとして登録されたらResourcesフォルダに移動します。

このViewがどのコントローラークラスに所属するかを指定します。
Tools > Identity Inspector を起動して、File's Ownerを選択>ClassにMyViewControllerを指定します。
File's Ownerにアウトレット(nibファイル内の項目に接続しているインスタンス変数)を設定します。
File's OwnerをCtrlクリックしながらViewまでドラッグすればOKです。

Tool > Attribute Inspector から BackgroundColorを変更してシミュレーターで動かすと、このViewが正しく読み込まれているのがわかります。

次はビューにオブジェクトを追加します。

2008年12月23日火曜日

iPhoneで動かすHelloWorld その1

とりあえずHelloWorld的なものを作ってみよう!
とはいってもDeveloperCenterのiPhoneアプリケーションチュートリアルを実行しながらメモるだけですが :)

まずは最低限必要なCocoaのデザインパターンの説明をざっくりと

・Delegation
オブジェクトが、デリゲートとして指定された別のオブジェジェクトに定期的にメッセージを送信し、入力の要求やイベントの発生を通知するデザインパターン。
このデザインパターンはクラス継承の代替手段として、再利用可能なオブジェクトの機能を拡張するために使用する。

使用される場所:メイン処理の終了感知、ビューのセットアップ&管理、テキストフィールドのReturnイベント処理等

・Model-View-Controller
いわゆるMVC。
Model=データ、オブジェクト
View=ユーザインターフェース部分
Controller=ModelとViewを仲介する部分

・Target-Action
コントロールオブジェクトから、別のオブジェクトにメッセージの送信と、送信されたメッセージを受け取って処理する仕組み。

使用される場所:ボタン押す>Controllerへ指示


次に、Xcodeを起動して新規プロジェクトの作成を選択。
Windows-Based Applicationを選択。
とりあえず「ビルドして進行」するとiPhoneシミュレーターが立ち上がって白い画面が出たらOK

まずはどのようにアプリケーションが起動して画面が出て行くのかを追ってみよう!
main.m をみるとUIApplicationMainを起動しているだけなのがわかりました。
UIApplicationMainは info.plist 内の MainNibFile 値のインターフェースを起動します。
デフォではMainWindowになっているので、MainWIndow.xibが読み込まれます。
(前回はここの関連が?だった)

MainWindowをダブルクリックするとインターフェースビルダーが起動します。
そこに含まれる4つの項目は以下のような意味をもっています。
・File'sOwner
 UIApplicationのインスタンスです。
・First Responder
 イベント処理、今はまだ使用しません。
・[アプリケーション名]AppDelegate
 アプリケーションのデリゲートインスタンス
・WIndow
 実際の画面に表示されるウインド

アプリケーションは起動が完了すると applicationDidFinishLaunching をデリゲートに送信します。
デフォルトで作成されるこのメソッド処理を見てみます。

- (void)applicationDidFinishLaunching:(UIApplication *)application {

// Override point for customization after application launch
[window makeKeyAndVisible];
}

windowを定義してるだけですね。

次回はここへ、デフォルト以外のViewを追加してみます。

2008年12月21日日曜日

Objective-Cにおけるメモリ管理なんて怖くない!その2

前回、retain , release と dealloc でインスタンスのメモリ管理をやりました。
deallocで関連するインスタンスの解放をするのは良いとしても、 release 自体も忘れてしまったりする事があります。

Objective-Cでは autorelease という仕組みがあるそうなのでそこを見ていきます。
NSAutoreleasePool クラスを使って実現します。
NSAutoreleasePool は、自動解放されるべきインスタンスを保持しておくクラスです。
クラスが定義されると、 autorelease対象の広場(プール)が作成されます。
広場が存在する状態で、他クラスのインスタンスに autorelease を送ると、そのインスタンスは広場にほうりこまれます。
(広場に存在するだけで参照されているわけではないので、インスタンスのリファレンスカウンタは変わらない)

広場の release を実行すると、広場に存在するインスタンスすべてに release が実行されます。


id pool=[[NSAutoreleasePool alloc] init]; // 広場の作成

id foo=[[Foo alloc] init]; // Fooクラスのインスタンス作成。foo のリファレンスカウンタは1
[foo autorelease]; // foo インスタンスを広場に登録する。リファレンスカウンタは1のまま

[pool release]; // foo にもreleaseが実行される


NSAutoreleasePool は、複数存在してもよい。
複数存在する場合に autorelease を実行した場合は、一番近い所で指定されたプールへほうりこまれる。
基本は開始と終了でメインの pool を作り、内部でループなど一時的なインスタンスを作成する場所で子プールを作成する。


id mainPool=[[NSAutoreleasePool alloc] init];

id hoge=[[Hoge alloc] init];
[hoge autorelease]; // mainPool へ登録される

while(条件) {
id subPool=[[NSAutoreleasePool alloc] init];

id foo=[[Foo alloc] init];
[foo autorelease]; // subPool へ登録される

[subPool release];
}

[mainPool release];


CocoaのGUIアプリケーションはNSApplicationがイベント発生時(マウスクリック等)に子プールを作成して、イベント終了時にreleaseしてくれるので、それほど気にしなくても自動でやってくれる。
iPhoneSDKもそうなのかな?


・オーナーシップとメモリ管理
init~~ で呼ばれるメソッドはオーナーシップが定義される。(メモリの管理をする必要がある)
同等のメソッドで init がない場合は一時的なインスタンスとなり、 autorelease に登録される。

例:文字列を扱うNSStringクラスの場合

-(id)initWithUTF8String:(const char *)bytes
+(id)stringWithUTF8String:(const char *)bytes

どちらも文字列を保持するオブジェクトが作成されるが、initは生成したオブジェクトがオーナーとなり、
stringはプールへ登録される(autoreleaseが実行される)

オーナーシップを与えないコンストラクタをコンビニエンスコンストラクタと呼ぶ。

・シングルトンの定義
定数やシングルトンを作成する為には、retain,release,retainCountの機能を上書きする必要がある。
retainとreleaseを何もしないメソッドにし、retainCountは常に UINT_MAX を返すようにする。

2008年12月20日土曜日

Objective-Cにおけるメモリ管理なんて怖くない!

Object-C2.0でのメモリ管理には2種類の方法がある。

・リファレンスカウンタ方式
・ガーベジコレクション

ガーベジコレクションは2.0から採用された自動メモリ管理の仕組みで、Javaのガーベジコレクションと同じ要領である。
一定時間毎に不必要な(参照されていない)クラスを探しだし、解放していく。
これは後にとっておくとして・・・

まずはリファレンスカウンタ方式から詳しく見ていく。
一言でいうと、クラスがいくつ参照されているかをカウンタで管理し、0になったらメモリを解放するという仕組みである。

具体的には alloc init された時点で、インスタンスはカウンタを1とする。

以下例:

id foo = [[Foo alloc] init]; // fooインスタンにカウント1が刻まれる
[foo release]; // fooインスタンスのカウントは0となり、メモリがリリースされる

id foo2 = [[Foo alloc] init]; // foo2インスタンスにカウント1が刻まれる
id hoge = [[Hoge alloc] init];
[hoge setFoo:[foo2 retain]]; // HogeインスタンスにはsetFooでfooを参照する機能がある。この時点でfoo2インスタンスにカウント2が刻まれる

[foo2 release]; // foo2のカウントが1に減る
[foo2 release]; // foo2のカウントが0となり、メモリがリリースされる


・retain メソッドでカウントを+1する。このメソッドは自身を返す。
・release メソッドでカウントを−1する。
・現在のカウント数は retainCount メソッドで見る事が出来る。
・dealloc でメモリをリリース出来るが、これはカウンタに関係なくリリースされてしまうので使うべきではない。

でもいちいち手動でリリースしてたらきりがない!
そこで dealloc をオーバーライドして、インスタンスが解放される時にインスタンスが保持するオブジェクトをリリースするのだ。

以上をふまえて簡単なテストプログラム

ReferenceCounterクラス

#import

@interface ReferenceCounter : NSObject {
id obj;
}
-(void)setObj:(id)_obj;
@end


@implementation ReferenceCounter
-(void)setObj:(id)_obj {
obj=[_obj retain]; // 何かオブジェクトがセットされる。ただ代入するのではなく、使用するよ!とカウンタを+する。
}

-(void)dealloc {
[obj release]; // 自身がリリースされるまえに、自分がもってるオブジェクトをリリースする。
[super dealloc]; // 自身のリリース
}

@end


int main(int argc, char *argv[]) {

id foo=[[NSObject alloc] init];
printf("retainCount: %d\n",[foo retainCount]);

id rctest=[[ReferenceCounter alloc] init]; // テストクラスを作成
[rctest setObj:foo]; // テストクラスになんかオブジェクトをセットする
printf("retainCount: %d\n",[foo retainCount]);

[foo release]; // オブジェクトをリリース
printf("retainCount: %d\n",[foo retainCount]);

[rctest release]; // テストクラスをリリース

return 0;
}


・foo インスタンスが alloc されて foo = 1 カウンタがつく
・rctest インスタンスが alloc されて rctest = 1 カウンタがつく
・rctest に foo をセットする。setter内で foo を retain するので foo=2 になる
・foo インスタンスを release する。 foo=1 になる
・rctest をリリースする。rctest=0になり、dealloc がよばれ rctest内のobj(foo)がreleaseされる。 foo=0になる

出力は以下のような感じ
retainCount: 1
retainCount: 2
retainCount: 1

なるほど、オブジェクト思考っぽい。
この考えは普通にJavaでも活かせる気がする!

2008年12月18日木曜日

不思議の国のアプリ(iPhone)

えー、メモリ管理をすっとばして、とりあえず今まで学んだ知識でiPhoneアプリのサンプルがどれぐらい理解できるか挑戦!

XCODEの新規プロジェクトからNavigation-BasedApplicationを作成してみる。

まずは main.m から


#import

int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}


あらスッキリ。
NSAutoreleasePoolでメモリ管理をしつつ、UIApplicationMainってのを起動しているだけっぽい?
ではUIApplicationMainを・・・って早速ここからどこにいってるのか・・・

そんなわけでiPhoneDeveloperCenterのGettingStartedを一生懸命斜め読み
どうやらUIApplicationMainからはMainWindow.xibが開かれるって事かな?
xibを開くとインターフェースビルダーが立ち上がる、、、おお、なんかおもしろい
して、このボタンのイベントなどはどこで設定するのやら・・・
うーん何がなんだかサッパリ、、、日本語の情報がほしー
DeveloperCenterの情報は豊富だけど、有料でもいいから日本語がほっすいよん
とりあえず来月日本語本出るみたいだし読んでみようかなー

覚えておくと便利なConfluenceのウラワザ

Confluenceの2.9.2を入れて数日、日本語で検索をした時にエラーが出ます。

エラーメッセージを見ると StringIndexOutOfBounds エラーが出ているもよう。

・英語での検索はエラーが出ない
・前のバージョンと比べて、検索結果でハイライトされるようになった

以上の結果から検索結果の文字をハイライトする時の文字数計算が2バイト考慮されてなくてエラーが出てるのではないかと推測

まずは検索結果の decorators/components/search-results.vmd を見てみる
該当部分は以下

<ul class="search-results">
#foreach($searchResult in $results)
<li>
#searchResult($searchResult $showExcerpts $queryString)
</li>
#end
</ul>


searchResultを消してしまうと検索結果がでないので、この searchResultがどこにあるかを探っていくと、以下にたどりついた
template/includes/macros.vm
該当部分は以下

#set ($summary = $generalUtil.makeSummary($contentBody, $queryString))
#elseif ($searchResult.type == "attachment" && $contentBody)
#set ($summary = $generalUtil.makeSummary($contentBody, $queryString))
#elseif ($searchResult.type == "attachment" && $searchResult.comment)
#set ($summary = $generalUtil.makeSummary($searchResult.comment, $queryString))


GeneralUtilクラスのmakeSummaryがダメダメっぽい

APIを見てみる > http://docs.atlassian.com/com/atlassian/confluence/atlassian-confluence/latest/com/atlassian/confluence/util/GeneralUtil.html

Summary型を返さないといけないので、ここをはぶいてしまうと検索は出来るけど、検索結果がページタイトルしかでなくなってしまう
makeSummaryを見てみると、 content だけをうけとるのと、 contentとqueryを受け取るメソッドがあるのがわかる。
queryのハイライトが問題なんで、contentだけを渡すメソッドに書き換えてみる。


#set ($summary = $generalUtil.makeSummary($contentBody))
#elseif ($searchResult.type == "attachment" && $contentBody)
#set ($summary = $generalUtil.makeSummary($contentBody))
#elseif ($searchResult.type == "attachment" && $searchResult.comment)
#set ($summary = $generalUtil.makeSummary($searchResult.comment))


ここのテンプレートは再起動しないと反映されないので、confluenceを再起動。
検索してみると、無事検索がとおり、検索結果にページタイトルと中身の一部が表示された! :D

2008年12月17日水曜日

いまさら聞けない「Objective-C」超入門 Objective-C その4

そんなこんなで第4回。

動的結合ってなんじゃ?
・存在しないメソッドを実行しようとしたコードを書いた場合に、コンパイル時にエラーが出ず、実際に実行したときにメソッドが実行出来るかを確認する方式を「動的結合」と呼ぶ
・Javaは比較的静的結合、Groovyみたいにダイナミックに扱う場合は動的結合、という認識でいいのかな?

Object は id として扱うとしてきたが、普通にクラス名で宣言してもよい

Class Fooがあったとして
id c;
c=[Foo alloc];

Foo *c;
c=[Foo alloc];
どちらでもFooのインスタンスを作成出来る。

クラス名をしておくと、不正なクラス利用をされていた場合にコンパイル時にチェックしてくれる。
ダイナミックにクラスが変わる場合は id を使うって事ね!

nilについて
・nilはポインタが空の状態、NULLとは違う
・Classのinitに失敗した場合等に nilとなる
・JavaでNullになんかすると NullPointerException が出るが、 nil にメッセージを送ってもエラーにならない(ただしプログラム上ではわかりやすくする為に nil 判定を書いておく事は重要)

インターフェース内のクラス指定について
Objectの中に別のClassを持つ場合、 importして書く事も出来るが、通常は @class 宣言を使う。


@class Hoge;

@interface Foo : NSObject {
Hoge *ho;
}


HogeはClassだよと教えてやるわけです。ただし実装部では import する必要があります。

変数hogeにgetter , setter を定義する場合
-(int)hoge;
-(void)setHoge:(int)value;
getterにはgetを付けない!

Class型って?
・インスタンス化されたものじゃなくて、元となるクラス
・NSObjectに用意された class を呼ぶと、そのクラスのClass型を取得できる
これを使って動的にクラスを割り当てるサンプル!

Class theClass = flag ? [Foo class] : [Hoge class];
id v = [theClass alloc];


flagがtrueなら v はFooのインスタンスになり、falseなら v はHogeのインスタンスとなる。

インスタンスのクラスが指定したクラスのインスタンスかをチェックするには isMemberOfClass を使う。
BOOL isFoo = [v isMemberOfClass:[Foo class]];
v がFooのインスタンスであれば isFoo は true となる。

クラスメソッドとは?
・Javaでいうところのstaticメソッド?
・NSObjectには、class とか isMemberOfClass とか、alloc がクラスメソッドとして定義してあるため、上記のように使える
・自分でクラスメソッドを定義するには、今まで - と書いてた所を + と書く
例:allocの定義
+(id)alloc;

クラス内から、自分のクラスメソッドを呼ぶとき等は、
[[Foo alloc] say];
と書いてしまうと、Fooを継承したクラスで不都合が起きてしまうので
[[[self class] alloc] say];
とすれば、必ず呼ばれた時のクラスのクラスメソッドを呼ぶ事が出来る。

今日はこの辺りで・・・、次回はやっとメモリ関係

2008年12月16日火曜日

いまさら聞けない「Objective-C」超入門 Objective-C その3

そんなこんなで継承について

スーパークラスとかサブクラスとか継承の考え方はJavaとまったく一緒、省略
Cocoa環境では基本的にNSObjectというのがルートクラスとなる。JavaでいうObject的なものっぽい。
C++にはこういったすべてのベースとなるルートクラスがないらしい(!)

では実際に以下のような継承クラスを作成してみる
Parent = ルートクラス callNumber(int) で value に値をセットし、受け取った値を返す
Child = Parentのサブクラス、callNumber(int) をオーバーライドし、 受け取った2倍の値を返す
Grandchild = Childのサブクラス、callNumberでセットされた value の3倍の値を返す anotherNumber メソッドを追加

Parent.h

#import

@interface Parent : NSDocument {
int value;
}
- (int)callNumber:(int)num;

@end


Parent.m

#import "Parent.h"

@implementation Parent
- (int)callNumber:(int)num {
value=num;
return num;
}

@end


Child.h

#import
#import "Parent.h"

@interface Child : Parent {
}
-(int)callNumber:(int)num;

@end


Child.m

#import "Child.h"

@implementation Child
-(int)callNumber:(int)num {
value=num;
return num * 2;
}

@end


Grandchild.h

#import
#import "Child.h"

@interface Grandchild : Child {
}
-(int)anotherNumber;

@end


Grandchild.m

#import "Grandchild.h"

@implementation Grandchild
-(int)anotherNumber{
return value * 3;
}
@end


そしてこれらを実行して結果を出力する main.m
せっかくなんで入力された文字のキーコードを出力する q で終了


#import
#import "Parent.h"
#import "Child.h"
#import "Grandchild.h"

int main(void)
{
id p,c,g;
char buf[8];

p=[Parent alloc];
c=[Child alloc];
g=[Grandchild alloc];

while(scanf("%s",buf) > 0) {
switch(buf[0]) {
case 'q':return 0; break;
default:
printf("parent class >> %d\n",[p callNumber:buf[0]]);
printf("child class >> %d\n",[c callNumber:buf[0]]);
[g callNumber:buf[0]];
printf("grandchild class >> %d\n",[g anotherNumber]);
break;
}
}

return 0;
}


今日のポイント
Javaと違う所!
interfaceはクラスには必ず存在し、Javaのように同じインターフェースを持った別のクラスみたいな考えではない
同じような事をやる場合はインターフェース用のクラスを作成する、もちろんクラスだからインターフェースもいる
インターフェース用クラスのインターフェースとかどんだけ〜

なんで import は h ファイルだけでいいのか、昨日の謎がとけた!
早くぐりぐり動かしたいな〜

2008年12月15日月曜日

いまさら聞けない「Objective-C」超入門 Objective-C その2

とりあえず前回動かしたクラスを別々のファイルにする。

インターフェース部を クラス名.h でヘッダファイルとして、実装クラスを クラス名.m とするのが一般的らしい。
クラス名.m には クラス名.h を import する。
別の実装を各場合も クラス名.h を import すればおk。

main.h 内は main だけ残して、Helloクラスを別ファイルにする
main から import するのは クラス名.h だけでおk。何でだろう?同クラス名をデフォの実装として読み込んでくれる?

Hello.h


#import

@interface Hello : NSDocument {
int val;
int min,max,step;
}
- (id)initWithMin:(int)a max:(int)b step:(int)s;
- (int)value;
- (id)up;
- (id)down;
@end



Hello.m


#import "Hello.h"

@implementation Hello
- (id)initWithMin:(int)a max:(int)b step:(int)s {
self=[super init]; // NSObjectの初期化を呼ぶ
if(self!=nil) { // nilはnullみたいなもん? init が成功していたら
val=min=a;
max=b;
step=s;
}
return self;
}

- (int)value {
return val;
}

- (id)up {
if((val += step) > max) val=max;
return self;
}

- (id)down {
if((val -= step) < min) val=min;
return self;
}
@end



main.m


#import
#import "Hello.h"

int main(void)
{
id v,w;

v=[[Hello alloc] initWithMin:0 max:10 step:2];
w=[[Hello alloc] initWithMin:0 max:9 step:3];
[v up];
printf("%d %d\n",[v value], [w value]);
[v up];
[w up];
printf("%d %d\n",[v value], [w value]);

return 0;
}




Objective-CだからといってすべてをObject指向で作る必要はない
Object型より関数型の方が軽いため、あきらかな重い処理は関数型で作成した方が良い
関数定義のみを含むソースは .c ファイルとして扱う
ただしオブジェクトを引数や返り値としたり、メソッド呼び出しなどをする場合は .m とする

#import は複数のクラスを読み込んだ場合、かぶるヘッダファイルを読み込まない
#include は読み込む。(通常はヘッダファイル内で2度読み込まないように定義しておく)
2度読み込みたい事情が無い限り #import でおk

今日はここまで!次回はクラス継承

2008年12月14日日曜日

いまさら聞けない「Objective-C」超入門

というわけでObjective-Cはじめます。初心忘れるべからず。

・はじめに Objective-Cとはなんじゃらほい
 C言語にオブジェクト指向の機能を追加した言語
 MacOSX上で動作する言語、それ以外ではあまり使われない。iPhoneのアプリもObjective-Cで作成する 。
 C++もCにオブジェクト指向を追加した言語だが、Objective-Cとは別路線で互換性は無い
 Objective-Cの特徴としては、際立って柔軟性が高く、効率的なコードを書く事が出来るらしい
 Leopardの登場とあわせてObjective-C2.0(ガベージコレクション、宣言プロパティ、高速列挙を追加)が公開&実装された



なんとなく概要がわかった所でまずは触ってみよう

//オブジェクトは id という特殊な型
id obj

//オブジェクトにメッセージを送る(オブジェクトのメソッドを実行する?)
//この形をメッセージ式と呼ぶ。
[obj msg]

//objのmsgを呼び出した結果が戻り値となる
//以下のように、戻り値を使って別のメッセージを呼ぶ事も出来る
[[obj msg] msg2];
[[[obj msg] msg2] msg3];

// [] は配列としても使う、左側にあるもので自動的に判別される
array=[1,2,3]; // 配列の定義
el=test[[obj msg]]; // test配列の添字として [obj msg] の返り値を使う

//メッセージに引数が必要な場合はコロンを付ける
[obj msg:'yossy']

//メソッド一覧はメッセージセレクタと呼ばれる
//コロンの有無でも別のセレクタとして認識される
//コロンが引数的なキーワード
copy
copy:
delete
allDelete
create
findBookName:Author:

//クラスのインスタンス化
[クラス名 alloc]

//通常はinitするべし
//initがデフォ、initからはじまるメソッドでも良い
[[クラス名 alloc] init]

//インターフェースの作成
@interface Hello:NSObject
{
//インスタンス変数の宣言
}
// メソッドの宣言
- (id)delegate;
- (id)cellAtRow:(int)row column:(int)col;

@end

// this は self と表現される
//文字列を扱うのはちょっと面倒?
//とりあえず入門書に従って数値をいじるクラスが出来た・・・今日はタイムアップなり
// XCodeで新規Cocoaアプリケーション、mainに全部かきかき



#import

@interface Hello : NSDocument {
int val;
int min,max,step;
}
- (id)initWithMin:(int)a max:(int)b step:(int)s;
- (int)value;
- (id)up;
- (id)down;
@end

@implementation Hello
- (id)initWithMin:(int)a max:(int)b step:(int)s {
self=[super init]; // NSObjectの初期化を呼ぶ
if(self!=nil) { // nilはnullみたいなもん? init が成功していたら
val=min=a;
max=b;
step=s;
}
return self;
}

- (int)value {
return val;
}

- (id)up {
if((val += step) > max) val=max;
return self;
}

- (id)down {
if((val -= step) < min) val=min;
return self;
}
@end

//int main(int argc, char *argv[])
int main(void)
{
id v,w;

v=[[Hello alloc] initWithMin:0 max:10 step:2];
w=[[Hello alloc] initWithMin:0 max:9 step:3];
[v up];
printf("%d %d\n",[v value], [w value]);
[v up];
[w up];
printf("%d %d\n",[v value], [w value]);

// return NSApplicationMain(argc, (const char **) argv);
return 0;
}

2008年12月10日水曜日

報道されないConfluenceの裏側

Confluenceの移行をしていてハマったのでめもめも

・Confluenceはメジャーバージョンが変わると復元が出来ない
・フルバックアップが2GBを超える場合は処理出来ない(おいおい)

さて困った

とりえあずスペースでバックアップして復元してみると、メジャーバージョンが違うからだめだよ。と・・・
バックアップファイルを解凍して中を覗いてみると、exportDescriptor.properties の buildNumber というそれっぽいものを発見
とりあえずこれを新しいバージョンのbuildNumberにかえてインポートしてみる・・・できた! :D

ユーザとかはDBから直接もってきたりしたけどNGだった :(
同じユーザIDでユーザを作ってやると履歴とかはちゃんと表示されたので、ちょっと安心

しかし無理矢理感がいなめない・・・なんか正しい移行方法があるのかぁ

人生に役立つかもしれないpostgresについての知識

今日もまたよくやるけど、よく忘れるメモ

postgresで外部から接続出来るようにする(ローカル内のpgAdminとかからサックリ操作出来るようにする)

pg_hba.conf でアクセス制限をつける。
下の方にある行を書き換える

サンプル


# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 192.168.0.0 255.255.255.0 trust


日本語訳:とりあえず 192.168.0 シリーズからと、ローカルからなんでもばっちこいやー

postgresql.conf の設定


#---------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#---------------------------------------------------------------------------

# - Connection Settings -

listen_addresses = '*' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost', '*' = all


の部分の listen_addresses がデフォだと localhost になるんで、ここのコメントアウトをはずし、 * (すべて許可)にする

で、postgresを再起動してやればOK

2008年12月9日火曜日

いとしさと切なさとCnetOS on Confluence 

CentOSにGlassFishのせてConfluenceしてみよう

まずjdk5インスコ

jdk-1_5_0_16-linux-i586-rpm.bin
を落としてくれば実行するだけでおk

デフォのjava1.4をリプレイスしとく
mv /usr/bin/java /usr/bin/java_14
ln -s /usr/java/jdk1.5.0_16/bin/java /usr/bin/java

JAVA_HOMEの設定も忘れずに

お次にGlassFishインスコ
http://download.java.net/glassfish/v3-prelude/release/glassfish-v3-prelude-ml.zip
をダウンロードしてきて、適当な場所に解凍
解凍したフォルダ/bin/asadmin start-domain
で起動

でもってConfluenceインスコ
最新版は2.10ですが、日本語環境は2.9なので、2.9をダウンロードします
http://www.atlassian.com/software/confluence/downloads/binary/confluence-2.9.1.tar.gz
日本語化パッケージ
http://www.atlassian.co.jp/software/confluence/confluence-ja-2.9.0.jar

解凍したら confluence/WEB-INF/lib に上記日本語パッケージをコピーします

confluence/WEB-INF/classes/confluence-init.properties
で、データ保存場所を指定
sh build.sh
を実行すると dist/confluence-2.9.war が作成される。

作成されたファイルを glassfish へデプロイする
cp dist/confluence.war /usr/local/glassfish/glassfish/domains/domain1/autodeploy
この時 war の名前がコンテキスト名になるので、好きな名前に変えておくよろし

http://server:8080/confluence
にアクセスするとConfluenceのセットアップウィザードが立ち上がれば後は煮るなり焼くなり!

今日のCentOSスレはここですか

CentOSをインストール、サーバにしたいのでGUI系は全部カット

よくやるけど結構忘れるファイヤーウォールの設定、めもめも

/etc/sysconfig/iptables

のファイルに追記する。

-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
で排除されるので、この行より前に

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
みたいな感じで指定する。↑は port 80 なので http サーバ用

/etc/init.d/iptables restart
で即反映、しなくても再起動したら反映される :)